-- MMModules.mesa; edited by Forrest, July 15, 1980 2:45 PM
DIRECTORY
BcdDefs USING [NullLink, UnboundLink],
ControlDefs USING [
ControlLink, EPRange, FrameCodeBase, FrameHandle, GFT, GFTIndex,
GFTItem, GlobalFrameHandle, MainBodyIndex, LastAVSlot, NullEpBase,
NullFrame, NullGlobalFrame, PrefixHandle],
FrameDefs USING [
EnterGlobalFrame, EnumerateGlobalFrames, RemoveGlobalFrame, SwapInCode],
FrameOps USING [
Alloc, FrameSize, Free, GetReturnFrame, SetReturnLink],
InlineDefs USING [BITAND, COPY],
MiscDefs,
MMOps,
MMSDEntries,
SDDefs USING [SD, sGFTLength],
SystemDefs USING [FreePages],
TrapDefs USING [UnboundProcedure];
MMModules: PROGRAM
IMPORTS FrameDefs, FrameOps, InlineDefs, SystemDefs, TrapDefs
EXPORTS FrameDefs, MiscDefs, MMOps, MMSDEntries = PUBLIC BEGIN
OPEN ControlDefs;
-- Global Frame Table management
gftrover: CARDINAL ← 0; -- okay to start at 0 because incremented before used
NoGlobalFrameSlots: PUBLIC SIGNAL [CARDINAL] = CODE;
EnumerateGlobalFrames: PUBLIC PROCEDURE [
proc: PROCEDURE [GlobalFrameHandle] RETURNS [BOOLEAN]]
RETURNS [GlobalFrameHandle] =
BEGIN
i: GFTIndex;
frame: GlobalFrameHandle;
gft: POINTER TO ARRAY [0..0) OF GFTItem ← GFT;
FOR i IN [0..SDDefs.SD[SDDefs.sGFTLength]) DO
frame ← gft[i].frame;
IF frame # NullGlobalFrame AND gft[i].epbase = 0
AND proc[frame] THEN RETURN[frame];
ENDLOOP;
RETURN[NullGlobalFrame]
END;
EnterGlobalFrame: PUBLIC PROCEDURE [
frame: GlobalFrameHandle, nslots: CARDINAL]
RETURNS [entryindex: GFTIndex] =
BEGIN
gft: POINTER TO ARRAY [0..0) OF GFTItem ← GFT;
i, imax, n, epoffset: CARDINAL;
i ← gftrover; imax ← SDDefs.SD[SDDefs.sGFTLength] - nslots; n ← 0;
DO
IF (i ← IF i>=imax THEN 1 ELSE i+1) = gftrover
THEN SIGNAL NoGlobalFrameSlots[nslots];
IF gft[i].frame # NullGlobalFrame THEN n ← 0
ELSE IF gft[i].epbase = NullEpBase THEN n ← 0
ELSE IF (n ← n+1) = nslots THEN EXIT;
ENDLOOP;
entryindex ← (gftrover←i)-nslots+1; epoffset ← 0;
FOR i IN [entryindex..gftrover] DO
gft[i] ← GFTItem[frame, epoffset];
epoffset ← epoffset + EPRange;
ENDLOOP;
RETURN
END;
RemoveGlobalFrame: PUBLIC PROCEDURE [frame: GlobalFrameHandle] =
BEGIN
gft: POINTER TO ARRAY [0..0) OF GFTItem ← GFT;
sd: POINTER TO ARRAY [0..0) OF CARDINAL ← SDDefs.SD;
i: CARDINAL;
FOR i ← frame.gfi, i+1
WHILE i<sd[SDDefs.sGFTLength] AND gft[i].frame=frame DO
gft[i] ← IF frame.copied THEN
GFTItem[NullGlobalFrame,0] ELSE GFTItem[NullGlobalFrame,NullEpBase];
ENDLOOP;
RETURN
END;
-- Frame manipulation
InvalidGlobalFrame: PUBLIC SIGNAL [frame: GlobalFrameHandle] = CODE;
ValidateGlobalFrame: PUBLIC PROCEDURE [g: GlobalFrameHandle] =
BEGIN
IF ~ValidGlobalFrame[g] THEN SIGNAL InvalidGlobalFrame[g];
END;
ValidGlobalFrame: PROCEDURE [g: GlobalFrameHandle]
RETURNS[BOOLEAN] =
BEGIN
i: CARDINAL;
gft: POINTER TO ARRAY [0..0) OF GFTItem ← GFT;
IF LOOPHOLE[g, ControlLink].tag # frame THEN RETURN[FALSE];
FOR i IN [1..SDDefs.SD[SDDefs.sGFTLength]) DO
IF gft[i].frame = g THEN EXIT;
REPEAT FINISHED => RETURN[FALSE];
ENDLOOP;
RETURN[gft[g.gfi].frame = g]
END;
InvalidFrame: PUBLIC SIGNAL [frame: FrameHandle] = CODE;
ValidateFrame: PUBLIC PROCEDURE [f: FrameHandle] =
BEGIN
IF ~ValidFrame[f] THEN SIGNAL InvalidFrame[f];
END;
ValidFrame: PROCEDURE [f: FrameHandle]
RETURNS[BOOLEAN] =
BEGIN
RETURN[LOOPHOLE[f, ControlLink].tag = frame
AND ValidGlobalFrame[f.accesslink]]
END;
GlobalFrame: PUBLIC PROCEDURE [link: UNSPECIFIED]
RETURNS [GlobalFrameHandle] =
BEGIN OPEN l: LOOPHOLE[link, ControlLink];
DO SELECT l.tag FROM
frame =>
BEGIN
IF link = 0 THEN RETURN[NullGlobalFrame];
IF ValidGlobalFrame[link] THEN RETURN[link];
IF ValidGlobalFrame[l.frame.accesslink] THEN
RETURN[l.frame.accesslink];
RETURN[NullGlobalFrame]
END;
procedure => RETURN[GFT[l.gfi].frame];
indirect => link ← l.link↑;
unbound => link ← SIGNAL TrapDefs.UnboundProcedure[link];
ENDCASE ENDLOOP
END;
Copy: PUBLIC PROCEDURE [old: GlobalFrameHandle]
RETURNS [new: GlobalFrameHandle] =
BEGIN
linkspace, ngfi: CARDINAL ← 0;
FrameDefs.SwapInCode[old];
[new, linkspace, ngfi] ← AllocGlobalFrame[old];
new ← new + linkspace;
new↑ ← [gfi:, unused: 0, alloced: TRUE, shared: TRUE, copied: TRUE,
started: FALSE, trapxfers: FALSE, codelinks: old.codelinks,
code: old.code, global:];
new.gfi ← FrameDefs.EnterGlobalFrame[new, ngfi];
new.code.offset ← old.code.shortbase - old.code.handle;
new.code.out ← TRUE;
new.global[0] ← NullGlobalFrame;
old.shared ← TRUE;
IF linkspace # 0 THEN InlineDefs.COPY[
from: old-linkspace, to: new-linkspace, nwords: linkspace];
RETURN
END;
MakeFsi: PUBLIC PROCEDURE [words: CARDINAL] RETURNS [fsi: CARDINAL] =
BEGIN
FOR fsi IN [0..LastAVSlot] DO
IF FrameOps.FrameSize[fsi] >= words THEN RETURN;
ENDLOOP;
RETURN[words]
END;
AllocGlobalFrame: PROCEDURE [old: GlobalFrameHandle]
RETURNS [frame: GlobalFrameHandle, linkspace, ngfi: CARDINAL] =
BEGIN
pbody: POINTER;
cp: PrefixHandle ← old.code.shortbase;
pbody ← cp+CARDINAL[cp.entry[MainBodyIndex].initialpc];
linkspace ← IF ~old.codelinks THEN cp.header.info.nlinks +
InlineDefs.BITAND[-LOOPHOLE[cp.header.info.nlinks, INTEGER], 3B]
ELSE 0;
frame ← FrameOps.Alloc[MakeFsi[(pbody-1)↑+linkspace]];
ngfi ← cp.header.info.ngfi;
RETURN
END;
UnNew: PUBLIC PROCEDURE [frame: GlobalFrameHandle] =
BEGIN
nlinks: CARDINAL;
sharer: GlobalFrameHandle ← NullGlobalFrame;
original: GlobalFrameHandle ← NullGlobalFrame;
copy: GlobalFrameHandle ← NullGlobalFrame;
nothers: CARDINAL ← 0;
RemoveAllTraces: PROCEDURE [f: GlobalFrameHandle] RETURNS [BOOLEAN] =
BEGIN
cm: CodeMatch;
IF f#frame THEN
BEGIN
IF f.global[0] = frame AND ~f.started THEN f.global[0] ← NullFrame;
cm ← SameCode[f, frame];
IF cm # different THEN
BEGIN
nothers ← nothers + 1; sharer ← f;
IF cm = identical THEN
IF f.copied THEN copy ← f ELSE original ← f;
END;
END;
RETURN[FALSE];
END;
FrameDefs.SwapInCode[frame];
[] ← FrameDefs.EnumerateGlobalFrames[RemoveAllTraces];
FrameDefs.RemoveGlobalFrame[frame];
IF frame.shared THEN
BEGIN
IF nothers = 1 THEN sharer.shared ← FALSE
END
ELSE SystemDefs.FreePages[frame.code.handle];
IF frame.alloced THEN
BEGIN
Align: PROCEDURE [POINTER, WORD] RETURNS [POINTER] =
LOOPHOLE[InlineDefs.BITAND];
IF frame.codelinks THEN FrameOps.Free[frame]
ELSE FrameOps.Free[Align[frame - nlinks, 177774B]]
END;
END;
CodeMatch: TYPE = {identical, same, different};
SameCode: PROCEDURE [f1, f2: GlobalFrameHandle] RETURNS [cm: CodeMatch] =
BEGIN
fcb1, fcb2: ControlDefs.FrameCodeBase;
fcb1 ← f1.code;
fcb2 ← f2.code;
IF f1.code.handle # f2.code.handle THEN RETURN[different];
FrameDefs.SwapInCode[f1];
FrameDefs.SwapInCode[f2];
cm ← IF f1.code = f2.code THEN identical ELSE same;
IF ~f1.started THEN f1.code ← fcb1;
IF ~f2.started THEN f2.code ← fcb2;
RETURN
END;
LockCode, UnlockCode: PROCEDURE [link: UNSPECIFIED] = BEGIN END;
MakeCodeResident, SwapOutCode: PROCEDURE [f: GlobalFrameHandle] = LockCode;
GetCaller: PROCEDURE RETURNS [PROGRAM] =
BEGIN
RETURN[LOOPHOLE[FrameOps.GetReturnFrame[].returnlink.frame.accesslink]];
END;
IsBound: PROCEDURE [link: UNSPECIFIED] RETURNS [BOOLEAN] =
BEGIN
RETURN[link # BcdDefs.UnboundLink AND link # BcdDefs.NullLink];
END;
SelfDestruct: PROCEDURE =
BEGIN
destructee: FrameHandle ← FrameOps.GetReturnFrame[];
FrameOps.SetReturnLink[destructee.returnlink];
UnNew[GlobalFrame[destructee]];
FrameOps.Free[destructee];
RETURN
END;
SetBlock: PROCEDURE [p:POINTER, v:UNSPECIFIED, l:CARDINAL] =
BEGIN
IF l=0 THEN RETURN; p↑ ← v;
InlineDefs.COPY[from:p, to:p+1, nwords:l-1];
END;
Zero: PROCEDURE [p:POINTER, l:CARDINAL] =
BEGIN
IF l=0 THEN RETURN; p↑ ← 0;
InlineDefs.COPY[from:p, to:p+1, nwords:l-1];
END;
FakeModulesCode: PROCEDURE [p: PROGRAM] RETURNS [POINTER] =
BEGIN
frame: GlobalFrameHandle;
FrameDefs.SwapInCode[frame ← GlobalFrame[p]];
RETURN[frame.code.shortbase];
END;
END...