-- Modules.mesa Last edited by Sandman, July 1, 1980 8:22 AM
-- Copyright Xerox Corporation 1979, 1980
DIRECTORY
ControlDefs USING [
ControlLink, ControlModule, EntryInfo, EPRange, FrameCodeBase, FrameHandle,
GFT, GFTIndex, GFTItem, GlobalFrameHandle, MainBodyIndex, LastAVSlot,
NullControl, NullEpBase, NullFrame, NullGlobalFrame, PrefixHandle, PrefixInfo,
StateVector, SVPointer, WordPC],
FrameDefs USING [
EnterGlobalFrame, EnumerateGlobalFrames, RemoveGlobalFrame, SwapInCode,
ValidateGlobalFrame],
FrameOps USING [
Alloc, CodeHandle, FrameSize, Free, GetReturnLink, ReleaseCode,
SetReturnFrame, ValidGlobalFrame],
InlineDefs USING [BITAND, COPY],
LoadStateFormat USING [NullModule],
LoadStateOps USING [EnterModule, GetModule, InputLoadState, ReleaseLoadState],
Mopcodes USING [zDESCBS, zRBL, zSFC],
NucleusOps USING [],
Runtime USING [],
SDDefs USING [sCopy, SD, sGFTLength, sUnNew],
SDOps USING [],
SegmentDefs USING [
AddressFromPage, DeleteFileSegment, FileSegmentHandle, SwapError, Unlock],
TrapDefs USING [UnboundProcedure];
Modules: PROGRAM
IMPORTS FrameDefs, FrameOps, InlineDefs, LoadStateOps, SegmentDefs, TrapDefs
EXPORTS FrameDefs, FrameOps, NucleusOps, Runtime, SDOps, TrapDefs
SHARES ControlDefs =
BEGIN OPEN ControlDefs;
StartFault: PUBLIC SIGNAL [dest: UNSPECIFIED] = CODE;
MainBody: PROCEDURE [GlobalFrameHandle] RETURNS [ControlLink] = MACHINE CODE
BEGIN Mopcodes.zDESCBS, 0 END;
Call: PROCEDURE [ControlLink] = MACHINE CODE BEGIN Mopcodes.zSFC END;
Start: PUBLIC PROCEDURE [cm: ControlModule] =
BEGIN
state: StateVector;
state ← STATE;
IF ~cm.multiple THEN
BEGIN
IF cm.frame = NullGlobalFrame OR cm.frame.started THEN
ERROR StartFault[cm.frame];
FrameDefs.ValidateGlobalFrame[cm.frame];
StartCM[cm.frame.global[0], cm.frame, @state];
IF ~cm.frame.started THEN
BEGIN cm.frame.started ← TRUE; StartWithState[cm.frame, @state]; END
ELSE IF state.stkptr # 0 THEN SIGNAL StartFault[cm];
END
ELSE
BEGIN
StartCM[cm, NIL, NIL];
IF state.stkptr # 0 THEN SIGNAL StartFault[cm];
END;
RETURN
END;
StartCM: PROCEDURE [
cm: ControlModule, frame: GlobalFrameHandle, state: ControlDefs.SVPointer] =
BEGIN
SELECT TRUE FROM
cm = NullControl => RETURN;
cm.multiple =>
BEGIN
i, length: CARDINAL;
cm.multiple ← FALSE;
IF (length ← cm.list.nModules) = 0 THEN RETURN;
cm.list.nModules ← 0;
FOR i IN [0..length) DO
StartCM[[frame[cm.list.frames[i]]], frame, state]; ENDLOOP;
FrameOps.Free[cm.list];
END;
cm.frame.started => RETURN;
ENDCASE =>
BEGIN
control: ControlModule ← cm.frame.global[0];
IF control # cm THEN StartCM[control, frame, state];
IF ~cm.frame.started THEN
BEGIN
cm.frame.started ← TRUE;
IF frame # cm.frame THEN Call[MainBody[cm.frame]]
ELSE StartWithState[frame, state];
END;
END;
RETURN
END;
StartWithState: PROCEDURE [
frame: GlobalFrameHandle, state: ControlDefs.SVPointer] =
BEGIN OPEN ControlDefs;
s: StateVector ← state↑;
retFrame: FrameHandle ← FrameOps.GetReturnLink[].frame;
s.dest ← MainBody[frame];
s.source ← retFrame.returnlink;
FrameOps.Free[retFrame];
RETURN WITH s;
END;
Restart: PUBLIC PROCEDURE [dest: GlobalFrameHandle] =
BEGIN
stops: BOOLEAN;
frame: FrameHandle;
IF dest = NullGlobalFrame THEN ERROR StartFault[dest];
FrameDefs.ValidateGlobalFrame[dest];
IF ~dest.started THEN Start[[frame[dest]]];
FrameDefs.SwapInCode[dest];
IF dest.code.highByte = 0 THEN
BEGIN
GetPrefixInfo: PROCEDURE [LONG POINTER] RETURNS [PrefixInfo] = MACHINE CODE
BEGIN Mopcodes.zRBL, 1 END;
stops ← GetPrefixInfo[dest.code.longbase].stops;
END
ELSE stops ← LOOPHOLE[dest.code.shortbase, PrefixHandle].header.info.stops;
FrameOps.ReleaseCode[dest];
IF ~stops THEN ERROR StartFault[dest];
IF (frame ← dest.global[0]) # NullFrame THEN
BEGIN
frame.returnlink ← FrameOps.GetReturnLink[];
FrameOps.SetReturnFrame[frame];
END;
RETURN
END;
-- 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
GlobalFrame: PUBLIC PROCEDURE [link: UNSPECIFIED] RETURNS [UNSPECIFIED] =
BEGIN OPEN l: LOOPHOLE[link, ControlLink];
DO
SELECT l.tag FROM
frame =>
BEGIN
IF link = 0 THEN RETURN[NullGlobalFrame];
IF FrameOps.ValidGlobalFrame[link] THEN RETURN[link];
IF FrameOps.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;
long: BOOLEAN;
seg: SegmentDefs.FileSegmentHandle;
FrameDefs.ValidateGlobalFrame[old];
seg ← FrameOps.CodeHandle[old];
FrameDefs.SwapInCode[old];
IF (long ← old.code.highByte = 0) THEN
[new, linkspace, ngfi] ← AllocLongGlobalFrame[old]
ELSE [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];
IF seg # NIL THEN
BEGIN
new.code.offset ←
old.code.shortbase - SegmentDefs.AddressFromPage[seg.VMpage];
new.code.handle ← seg;
END;
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];
FrameOps.ReleaseCode[old];
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;
GetPrefixInfo: PROCEDURE [LONG POINTER] RETURNS [PrefixInfo] = MACHINE CODE
BEGIN Mopcodes.zRBL, 1 END;
GetEntryInfo: PROCEDURE [LONG POINTER] RETURNS [EntryInfo] = MACHINE CODE
BEGIN Mopcodes.zRBL, 1 END;
GetInitialPC: PROCEDURE [LONG POINTER] RETURNS [WordPC] = MACHINE CODE
BEGIN Mopcodes.zRBL, 0 END;
GetFSize: PROCEDURE [LONG POINTER] RETURNS [CARDINAL] = MACHINE CODE
BEGIN Mopcodes.zRBL, 0 END;
AllocLongGlobalFrame: PROCEDURE [old: GlobalFrameHandle]
RETURNS [frame: GlobalFrameHandle, linkspace, ngfi: CARDINAL] =
BEGIN
p: LONG POINTER;
fsi: CARDINAL;
initialpc: WordPC;
cp: LONG PrefixHandle ← old.code.longbase;
prefix: PrefixInfo ← GetPrefixInfo[cp];
entryInfo: EntryInfo;
p ← @cp.entry[MainBodyIndex];
entryInfo ← GetEntryInfo[p];
initialpc ← GetInitialPC[p];
p ← cp + initialpc - 1;
linkspace ←
IF ~old.codelinks THEN
prefix.nlinks + InlineDefs.BITAND[-LOOPHOLE[prefix.nlinks, INTEGER], 3B]
ELSE 0;
fsi ← GetFSize[p];
frame ← FrameOps.Alloc[MakeFsi[fsi + linkspace]];
ngfi ← prefix.ngfi;
RETURN
END;
UnNewModule: PROCEDURE [frame: GlobalFrameHandle] =
BEGIN
cseg: SegmentDefs.FileSegmentHandle;
sharer: GlobalFrameHandle ← NullGlobalFrame;
original: GlobalFrameHandle ← NullGlobalFrame;
copy: GlobalFrameHandle ← NullGlobalFrame;
fcb: FrameCodeBase;
nothers: CARDINAL ← 0;
nlinks: CARDINAL;
long: BOOLEAN;
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.ValidateGlobalFrame[frame];
cseg ← FrameOps.CodeHandle[frame];
FrameDefs.SwapInCode[frame];
fcb ← frame.code;
IF (long ← frame.code.highByte = 0) THEN
BEGIN
prefix: PrefixInfo ← GetPrefixInfo[frame.code.longbase];
nlinks ← prefix.nlinks
END
ELSE
BEGIN
nlinks ← LOOPHOLE[frame.code.shortbase, PrefixHandle].header.info.nlinks;
fcb.offset ←
frame.code.shortbase - SegmentDefs.AddressFromPage[cseg.VMpage];
fcb.out ← TRUE;
END;
[] ← FrameDefs.EnumerateGlobalFrames[RemoveAllTraces];
IF cseg # NIL THEN SegmentDefs.Unlock[cseg];
IF original = NullGlobalFrame AND ~frame.copied AND copy # NullGlobalFrame
THEN
BEGIN OPEN LoadStateOps;
copy.copied ← FALSE;
[] ← InputLoadState[];
EnterModule[rgfi: copy.gfi, module: GetModule[frame.gfi]];
EnterModule[rgfi: frame.gfi, module: LoadStateFormat.NullModule];
ReleaseLoadState[];
END;
IF frame.shared THEN BEGIN IF nothers = 1 THEN sharer.shared ← FALSE END
ELSE
IF cseg # NIL THEN
BEGIN OPEN SegmentDefs;
DeleteFileSegment[cseg ! SwapError => CONTINUE];
END;
FrameDefs.RemoveGlobalFrame[frame];
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
o1, o2: BOOLEAN;
seg1, seg2: SegmentDefs.FileSegmentHandle;
fcb1, fcb2: ControlDefs.FrameCodeBase;
seg1 ← FrameOps.CodeHandle[f1];
seg2 ← FrameOps.CodeHandle[f2];
fcb1 ← f1.code;
fcb2 ← f2.code;
IF seg1 = NIL AND seg2 = NIL THEN
BEGIN
fcb1.out ← fcb2.out ← FALSE;
RETURN[IF fcb1 = fcb2 THEN identical ELSE different];
END;
IF seg1 # seg2 THEN RETURN[different];
IF (o1 ← f1.code.out) AND (o2 ← f2.code.out) THEN
RETURN[IF f1.code = f2.code THEN identical ELSE same];
FrameDefs.SwapInCode[f1];
FrameDefs.SwapInCode[f2];
cm ← IF f1.code = f2.code THEN identical ELSE same;
SegmentDefs.Unlock[seg1];
SegmentDefs.Unlock[seg2];
IF ~f1.started THEN f1.code ← fcb1;
IF ~f2.started THEN f2.code ← fcb2;
RETURN
END;
Init: PROCEDURE =
BEGIN OPEN SDDefs;
sd: POINTER TO ARRAY [0..0) OF UNSPECIFIED ← SD;
sd[sCopy] ← Copy;
sd[sUnNew] ← UnNewModule;
END;
-- Main Body;
Init[];
END...