-- HeapPack.Mesa  Edited by: Bruce on August 29, 1980  1:27 PM

DIRECTORY
  DebugFormat USING [Fob, Foo],
  DOutput USING [Text],
  DHeap USING [Zero],
  Init USING [FlushCaches],
  Inline USING [LongNumber],
  Pc USING [CtxLink],
  State USING [DNode, Get, Handle, NodeHandle, NodeType],
  Storage USING [Expand, Free, Node, Prune],
  Table USING [WordsFree];

HeapPack: PROGRAM
  IMPORTS DOutput, Init, DHeap, State, Storage, Table
  EXPORTS DHeap, Init, Pc =
  BEGIN OPEN DebugFormat;
  
  MoreHeapSpace: CARDINAL = 7;
  NotInHeap: PUBLIC SIGNAL = CODE;
  InvalidNodeType: ERROR = CODE;

  FreeContextList: PUBLIC PROC [p: Pc.CtxLink] =
    BEGIN
    next: Pc.CtxLink;
    FOR p ← p, next UNTIL p = NIL DO next ← p.link; Storage.Free[p] ENDLOOP;
    END;

  AllocFob: PUBLIC PROCEDURE RETURNS [f: Foo] =
    BEGIN
    f ← MyAlloc[SIZE[Fob],fobs];
    DHeap.Zero[f, SIZE[Fob]];
    END;

  TopLevel: PUBLIC PROC = {MyFree[fobs]; [] ← Storage.Prune[]; CheckSymTabLength[]};

  FreeFobs: PUBLIC PROC = {MyFree[fobs]};

  CheckSymTabLength: PUBLIC PROC =
    BEGIN
    IF Table.WordsFree[] < 300 THEN
      BEGIN
      DOutput.Text[" Resetting symbol table! "L];
      Init.FlushCaches[flushSymbols];
      END;
    END;

  -- utilities

  FreeLong: PUBLIC PROC [p: LONG POINTER] =
    BEGIN OPEN Inline;
    ln: LongNumber ← LOOPHOLE[p];
    IF ln.highbits # 0 THEN {SIGNAL NotInHeap; RETURN};
    Storage.Free[LOOPHOLE[ln.lowbits]]
    END;

  Initialize: PUBLIC PROC = BEGIN Storage.Expand[MoreHeapSpace] END;

  FreeEverything: PUBLIC PROC = {FreeFobs[]};

  MyAlloc: PROC [nwords: CARDINAL, nt: State.NodeType] RETURNS [POINTER] =
    BEGIN
    h: State.Handle ← State.Get[];
    root: POINTER TO State.NodeHandle ← SELECT nt FROM
      fobs => @h.fobs,
      ENDCASE => ERROR InvalidNodeType;
    n: State.NodeHandle ← Storage.Node[SIZE[State.DNode]];
    n↑ ← [link: root↑, node: Storage.Node[nwords]];
    root↑ ← n;
    RETURN[n.node];
    END;

  MyFree: PROCEDURE [nt: State.NodeType] =
    BEGIN
    h: State.Handle ← State.Get[];
    first: POINTER TO State.NodeHandle ← SELECT nt FROM
      fobs => @h.fobs,
      ENDCASE => ERROR InvalidNodeType;
    i, next: State.NodeHandle;
    FOR i ← first↑, next UNTIL i = NIL DO
      next ← i.link;
      SELECT nt FROM
	fobs =>
	  BEGIN
	  f: Foo ← i.node;
	  IF ~f.there THEN FreeLong[f.addr.base];
	  END;
	ENDCASE;
      Storage.Free[i.node]; Storage.Free[i];
      ENDLOOP;
    IF first↑ # NIL THEN first↑ ← NIL;
    END;

  END.