-- 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...