-- ExecStorage.mesa
-- Edited by Levin, September 9, 1980 5:17 PM
-- Edited by Brotz, December 24, 1981 2:44 PM

DIRECTORY
AltoDefs USING [PageSize],
FSPDefs USING [AddToNewZone, BlockSize, DestroyZone, FreeNode, MakeNewZone,
MakeNode, NodeHeader, NodeSize, NoRoomInZone, PruneZone, ZoneHeader,
ZoneOverhead, ZonePointer, ZoneTooSmall],
LaurelExecImpDefs USING [],
Mopcodes USING [zBLT],
SegmentDefs USING [DataSegmentAddress, DataSegmentHandle, DefaultMDSBase,
HardDown, MakeDataSegment, VMtoDataSegment],
Storage USING [],
SystemDefs USING [Even, FreePages, Quad, SegmentSize];

ExecStorage: PROGRAM
IMPORTS FSPDefs, SegmentDefs, realSystemDefs: SystemDefs
EXPORTS SystemDefs, Storage, LaurelExecImpDefs =

BEGIN


SegmentListRec: TYPE = RECORD [next: SegmentList, base: POINTER];
SegmentList: TYPE = POINTER TO SegmentListRec;

segmentList: SegmentList ← NIL;

UsedNodeSize: FSPDefs.BlockSize = SIZE[inuse FSPDefs.NodeHeader];
FreeNodeSize: FSPDefs.BlockSize = SIZE[free FSPDefs.NodeHeader];
ZoneHeaderSize: FSPDefs.BlockSize = SIZE[FSPDefs.ZoneHeader];

execHeap: FSPDefs.ZonePointer ← NIL;
useCount: CARDINAL ← 0;

LargeNode: CARDINAL = 150;


-- Interface for Laurel Executive

clientWords: PUBLIC CARDINAL;


StartExecStorage: PUBLIC PROCEDURE =
BEGIN
useCount ← useCount + 1;
END; -- of StartExecStorage --


FinishExecStorage: PUBLIC PROCEDURE =
BEGIN
IF useCount = 0 THEN ERROR;
useCount ← useCount - 1;
IF useCount > 0 THEN RETURN;
UNTIL segmentList = NIL DO
FreePages[segmentList.base];
ENDLOOP;
IF execHeap # NIL THEN {FSPDefs.DestroyZone[execHeap]; execHeap ← NIL};
END; -- of FinishExecStorage --


-- SystemDefs (Storage) Interface for Laurel Client BCDs

AllocatePages, AllocateResidentPages, Pages: PUBLIC PROCEDURE [npages: CARDINAL]
RETURNS [base: POINTER] =
BEGIN
OPEN SegmentDefs;
seg: DataSegmentHandle ← MakeDataSegment[DefaultMDSBase, npages, HardDown];
seg.type ← 89;
base ← DataSegmentAddress[seg];
AddSegmentToList[base];
END; -- of AllocatePages, AllocateResidentPages, Pages --


AllocateSegment, AllocateResidentSegment, Words: PUBLIC
PROCEDURE [nwords: CARDINAL] RETURNS [base: POINTER] =
BEGIN
RETURN[AllocatePages[PgsForWords[nwords]]];
END; -- of AllocateSegment, AllocateResidentSegment, Words --


FreePages, FreeSegment, FreeWords: PUBLIC PROCEDURE [base: POINTER] =
BEGIN
RemoveSegmentFromList[base];
realSystemDefs.FreePages[base];
END; -- of FreePages, FreeSegment, FreeWords --


AddSegmentToList: PRIVATE PROCEDURE [base: POINTER] =
BEGIN
sl: SegmentList ← AllocateHeapNode[SIZE[SegmentListRec]];
sl↑ ← SegmentListRec[next: segmentList, base: base];
segmentList ← sl;
END; -- of AddSegmentToList --


RemoveSegmentFromList: PRIVATE PROCEDURE [base: POINTER] =
BEGIN
sl: SegmentList ← segmentList;
slPrev: SegmentList ← NIL;
UNTIL sl = NIL DO
IF base = sl.base THEN
{IF slPrev = NIL THEN segmentList ← sl.next ELSE slPrev.next ← sl.next; RETURN};
slPrev ← sl;
sl ← sl.next;
ENDLOOP;
END; -- of RemoveSegmentFromList --


SegmentSize: PUBLIC PROCEDURE [base: POINTER] RETURNS [nwords: CARDINAL] =
BEGIN
RETURN[realSystemDefs.SegmentSize[base]];
END; -- of SegmentSize --


HeapZone: PUBLIC PROCEDURE RETURNS [FSPDefs.ZonePointer] =
BEGIN
IF execHeap = NIL THEN InitHeap[];
RETURN[execHeap];
END; -- of HeapZone --


PruneHeap, Prune: PUBLIC PROCEDURE RETURNS [BOOLEAN] =
BEGIN
RETURN[execHeap # NIL AND FSPDefs.PruneZone[execHeap]];
END; -- of PruneHeap, Prune --


Even: PUBLIC PROCEDURE [u: UNSPECIFIED] RETURNS [UNSPECIFIED] =
BEGIN
RETURN[realSystemDefs.Even[u]];
END; -- of Even --


Quad: PUBLIC PROCEDURE [u: UNSPECIFIED] RETURNS [UNSPECIFIED] =
BEGIN
RETURN[realSystemDefs.Quad[u]];
END; -- of Quad --


Node, AllocateHeapNode: PUBLIC PROC [nwords: CARDINAL] RETURNS [p: POINTER] =
BEGIN OPEN FSPDefs;
IF execHeap = NIL THEN InitHeap[];
IF INTEGER[nwords] < 0 THEN ERROR ZoneTooSmall[execHeap];
IF nwords + UsedNodeSize > LargeNode THEN
BEGIN
p ← Pages[PgsForWords[nwords + UsedNodeSize]];
p↑ ← NodeHeader[length: nwords + UsedNodeSize, extension: inuse[]];
clientWords ← clientWords + FSPDefs.NodeSize[p + 1];
RETURN[p + 1]
END;
p ← MakeNode[execHeap, nwords ! NoRoomInZone =>
{Expand[PgsForWords[nwords + ZoneOverhead + UsedNodeSize]]; RESUME}];
clientWords ← clientWords + FSPDefs.NodeSize[p];
END; -- of Node, AllocateHeapNode --


Expand: PUBLIC PROCEDURE [pages: CARDINAL] =
BEGIN
FSPDefs.AddToNewZone[z: execHeap, base: GetMorePages[pages],
length: pages*AltoDefs.PageSize, deallocate: realSystemDefs.FreePages];
END; -- of Expand --


GetMorePages: PROCEDURE [pages: CARDINAL] RETURNS [POINTER] =
BEGIN OPEN SegmentDefs;
seg: DataSegmentHandle ← MakeDataSegment[DefaultMDSBase, pages, HardDown];
seg.type ← 89;
RETURN[DataSegmentAddress[seg]];
END; -- of GetMorePages --


Free, FreeHeapNode: PUBLIC PROCEDURE [p: POINTER] =
BEGIN OPEN SegmentDefs, FSPDefs;
pp: POINTER;
IF p = NIL THEN RETURN;
clientWords ← clientWords - FSPDefs.NodeSize[p];
IF LOOPHOLE[(pp ← p - 1), POINTER TO inuse NodeHeader].length > LargeNode
AND DataSegmentAddress[VMtoDataSegment[pp]] = pp THEN
{FreePages[pp]; RETURN};
FreeNode[execHeap, p];
END; -- of Free, FreeHeapNode --


String, AllocateHeapString: PUBLIC PROC [nchars: CARDINAL] RETURNS [s: STRING] =
BEGIN
s ← AllocateHeapNode[WdsForString[nchars]];
s↑ ← StringBody[length: 0, maxlength: nchars, text:];
RETURN[s]
END; -- of String, AllocateHeapString --


PgsForWords: PRIVATE PROC [nwords: CARDINAL] RETURNS [CARDINAL] = INLINE
{RETURN[(nwords + AltoDefs.PageSize - 1) / AltoDefs.PageSize]};


WdsForString: PRIVATE PROC [nchars: CARDINAL] RETURNS [CARDINAL] = INLINE
{RETURN[2 + (nchars + 1) / 2]};


FreeString, FreeHeapString: PUBLIC PROCEDURE [s: STRING] = LOOPHOLE[Free];


CopyString: PUBLIC PROCEDURE [s: STRING, longer: CARDINAL ← 0] RETURNS [STRING] =
BEGIN
ns: STRING;
IF s = NIL THEN RETURN[IF longer = 0 THEN NIL ELSE String[longer]];
ns ← AllocateHeapString[s.length + longer];
CPY[from: @s.text, to: @ns.text, nwords: (s.length + 1)/2];
ns.length ← s.length;
RETURN[ns];
END; -- of CopyString --


ExpandString: PUBLIC PROCEDURE [s: POINTER TO STRING, longer: CARDINAL ← 0] =
BEGIN
ns: STRING;
IF s↑ = NIL THEN {IF longer # 0 THEN s↑ ← String[longer]; RETURN};
ns ← AllocateHeapString[s.maxlength + longer];
CPY[from: @s.text, to: @ns.text, nwords: (s.length + 1)/2];
ns.length ← s.length;
FreeHeapString[s↑];
s↑ ← ns;
END; -- of ExpandString --


CPY: PRIVATE PROCEDURE [from: POINTER, nwords: CARDINAL, to: POINTER] =
MACHINE CODE {Mopcodes.zBLT};


InitHeap: PUBLIC PROCEDURE =
BEGIN
IF useCount = 0 THEN ERROR;
execHeap ← FSPDefs.MakeNewZone
[GetMorePages[2], 2*AltoDefs.PageSize, realSystemDefs.FreePages];
END; -- of InitHeap --


END. -- of ExecStorage --