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