-- UnNewConfig.mesa; edited by Johnsson on October 27, 1980 2:08 PM
-- Copyright Xerox Corporation 1979, 1980
DIRECTORY
BcdDefs USING [Base, MTIndex],
BcdOps USING [BcdBase, MTHandle, ProcessModules],
ControlDefs USING [
ControlLink, FrameCodeBase, GFT, GFTIndex, GFTItem, GFTNull,
GlobalFrameHandle, NullGlobalFrame, PrefixHandle, PrefixInfo, TrapLink,
UnboundLink],
FrameDefs USING [EnumerateGlobalFrames, GlobalFrame, SwapInCode, UnNew],
FrameOps USING [CodeHandle, Free],
InlineDefs USING [BITAND],
LoaderOps USING [CloseLinkSpace, OpenLinkSpace, ReadLink, WriteLink],
LoadStateFormat USING [ModuleInfo],
LoadStateOps USING [
AcquireBcd, ConfigIndex, EnterModule, EnumerateBcds, GetMap, GetModule,
InputLoadState, MapRealToConfig, ReleaseBcd, ReleaseLoadState, ReleaseMap,
Map, RemoveConfig],
Mopcodes USING [zRBL],
SegmentDefs USING [
DataSegmentAddress, DeleteFileSegment, FileSegmentHandle, SwapError, Unlock,
VMtoDataSegment],
SystemDefs USING [FreeSegment, SegmentSize];
UnNewConfig: PROGRAM
IMPORTS
BcdOps, FrameDefs, FrameOps, InlineDefs, LoaderOps, LoadStateOps, SegmentDefs,
SystemDefs
EXPORTS FrameDefs =
BEGIN OPEN ControlDefs;
ConfigIndex: TYPE = LoadStateOps.ConfigIndex;
Map: TYPE = LoadStateOps.Map;
BcdBase: TYPE = BcdOps.BcdBase;
GlobalFrameHandle: TYPE = ControlDefs.GlobalFrameHandle;
NullGlobalFrame: GlobalFrameHandle = ControlDefs.NullGlobalFrame;
FileSegmentHandle: TYPE = SegmentDefs.FileSegmentHandle;
UnNewConfig: PUBLIC PROCEDURE [link: UNSPECIFIED] =
BEGIN OPEN LoadStateOps;
config: ConfigIndex;
map: Map;
bcd: BcdBase;
frame: GlobalFrameHandle ← FrameDefs.GlobalFrame[link];
FindOriginal: PROCEDURE [f: GlobalFrameHandle] RETURNS [BOOLEAN] =
BEGIN
IF f # frame THEN
BEGIN
IF SameCode[frame, f] = identical AND ~f.copied THEN
BEGIN frame ← f; RETURN[TRUE] END;
END;
RETURN[FALSE];
END;
IF frame.copied THEN [] ← FrameDefs.EnumerateGlobalFrames[FindOriginal];
[] ← InputLoadState[];
[config: config] ← MapRealToConfig[frame.gfi];
bcd ← AcquireBcd[config];
map ← GetMap[config];
UnBindConfig[config, bcd, map];
CleanupFrames[map];
CleanupGFT[map];
RemoveConfig[map, config];
ReleaseMap[map];
ReleaseBcd[bcd];
ReleaseLoadState[];
RETURN
END;
CodeMatch: TYPE = {identical, same, different};
SameCode: PROCEDURE [f1, f2: GlobalFrameHandle] RETURNS [cm: CodeMatch] =
BEGIN
o1, o2: BOOLEAN;
seg1, seg2: 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;
DestroyCopy: PROCEDURE [f: GlobalFrameHandle] RETURNS [BOOLEAN] =
BEGIN FrameDefs.UnNew[f]; RETURN[FALSE]; END;
CleanupFrames: PROCEDURE [map: Map] =
BEGIN
seg: FileSegmentHandle;
frameSegment: POINTER ← NIL;
frame: GlobalFrameHandle;
i, ep: CARDINAL;
nlinks: [0..256);
FOR i IN [1..LENGTH[map]) DO
deleteSeg: BOOLEAN ← FALSE;
[frame: frame, epbase: ep] ← ControlDefs.GFT[map[i]];
IF frame = NullGlobalFrame OR ep # 0 THEN LOOP;
seg ← FrameOps.CodeHandle[frame];
IF ~EnumerateCopies[frame, DestroyCopy].shared AND seg # NIL THEN
deleteSeg ← TRUE;
IF frame.alloced THEN
BEGIN
Align: PROCEDURE [POINTER, WORD] RETURNS [POINTER] =
LOOPHOLE[InlineDefs.BITAND];
IF frame.codelinks THEN FrameOps.Free[frame]
ELSE
BEGIN
nlinks ← FindNLinks[frame, seg];
FrameOps.Free[Align[frame - nlinks, 177774B]];
END;
END
ELSE frameSegment ← frame;
IF deleteSeg THEN
SegmentDefs.DeleteFileSegment[seg ! SegmentDefs.SwapError => CONTINUE];
ENDLOOP;
IF frameSegment # NIL THEN SystemDefs.FreeSegment[frameSegment];
RETURN
END;
FindNLinks: PROCEDURE [frame: GlobalFrameHandle, seg: FileSegmentHandle]
RETURNS [nlinks: CARDINAL] =
BEGIN
FrameDefs.SwapInCode[frame];
IF frame.code.highByte = 0 THEN
BEGIN
GetPrefixInfo: PROCEDURE [LONG POINTER] RETURNS [PrefixInfo] = MACHINE CODE
BEGIN Mopcodes.zRBL, 1 END;
prefix: PrefixInfo ← GetPrefixInfo[frame.code.longbase];
nlinks ← prefix.nlinks;
END
ELSE nlinks ← LOOPHOLE[frame.code.shortbase, PrefixHandle].header.info.nlinks;
SegmentDefs.Unlock[seg];
RETURN;
END;
NextMultipleOfFour: PROCEDURE [n: UNSPECIFIED] RETURNS [UNSPECIFIED] =
BEGIN RETURN[n + InlineDefs.BITAND[-n, 3B]] END;
OP: TYPE = ORDERED POINTER;
UnBindConfig: PROCEDURE [config: ConfigIndex, bcd: BcdBase, map: Map] =
BEGIN OPEN LoadStateOps;
bmap: Map;
frameStart, frameEnd: OP;
UnBind: PROCEDURE [c: ConfigIndex] RETURNS [BOOLEAN] =
BEGIN
bindee: BcdBase;
IF c = config THEN RETURN[FALSE];
bindee ← AcquireBcd[c];
IF bindee.nImports # 0 THEN
BEGIN
bmap ← GetMap[c];
[] ← BcdOps.ProcessModules[bindee, AdjustLinks];
ReleaseMap[bmap];
END;
ReleaseBcd[bindee];
RETURN[FALSE]
END;
AdjustLinks: PROCEDURE [mth: BcdOps.MTHandle, mti: BcdDefs.MTIndex]
RETURNS [BOOLEAN] =
BEGIN
gfi: ControlDefs.GFTIndex = bmap[mth.gfi];
frame: GlobalFrameHandle = ControlDefs.GFT[gfi].frame;
changed: BOOLEAN;
AdjustCopies: PROCEDURE [f: GlobalFrameHandle] RETURNS [BOOLEAN] =
BEGIN [] ← AdjustFrame[f, mth]; RETURN[FALSE]; END;
IF frame = NullGlobalFrame OR mth.frame.length = 0 THEN RETURN[FALSE];
changed ← AdjustFrame[frame, mth];
IF changed AND frame.shared AND ~frame.codelinks THEN
[] ← EnumerateCopies[frame, AdjustCopies];
IF changed THEN
BEGIN
info: LoadStateFormat.ModuleInfo ← GetModule[gfi];
info.resolved ← FALSE;
EnterModule[rgfi: gfi, module: info];
END;
RETURN[FALSE]
END;
AdjustFrame: PROCEDURE [frame: GlobalFrameHandle, mth: BcdOps.MTHandle]
RETURNS [changed: BOOLEAN] =
BEGIN
i: CARDINAL;
link: ControlDefs.ControlLink;
changed ← FALSE;
LoaderOps.OpenLinkSpace[frame, mth];
FOR i IN [0..mth.frame.length) DO
link ← LoaderOps.ReadLink[i];
IF BoundHere[link, mth.frame.frag[i].vtag = var] THEN
BEGIN
link ← (SELECT link.tag FROM frame => TrapLink, ENDCASE => UnboundLink);
LoaderOps.WriteLink[i, link];
changed ← TRUE;
END;
ENDLOOP;
LoaderOps.CloseLinkSpace[frame];
RETURN
END;
BoundHere: PROCEDURE [link: ControlLink, var: BOOLEAN] RETURNS [BOOLEAN] =
BEGIN OPEN FrameDefs;
i: CARDINAL;
gfi: GFTIndex ← GFTNull;
IF var THEN RETURN[LOOPHOLE[link, OP] IN [frameStart..frameEnd)];
SELECT link.tag FROM procedure => gfi ← link.gfi; ENDCASE => RETURN[FALSE];
FOR i IN [1..LENGTH[map]) DO IF map[i] = gfi THEN RETURN[TRUE]; ENDLOOP;
RETURN[FALSE];
END;
IF bcd.nExports = 0 AND bcd.nModules # 1 THEN RETURN;
frameStart ← LOOPHOLE[GFT[map[1]].frame];
IF bcd.nModules = 1 THEN
BEGIN OPEN BcdDefs;
mth: BcdOps.MTHandle = @LOOPHOLE[bcd + bcd.mtOffset, Base][FIRST[MTIndex]];
frameEnd ← LOOPHOLE[frameStart + mth.framesize]
END
ELSE
BEGIN OPEN SegmentDefs;
frameStart ← LOOPHOLE[DataSegmentAddress[VMtoDataSegment[frameStart]]];
frameEnd ← LOOPHOLE[frameStart + SystemDefs.SegmentSize[frameStart]];
END;
[] ← EnumerateBcds[recentfirst, UnBind];
RETURN
END;
CleanupGFT: PROCEDURE [map: Map] =
BEGIN OPEN ControlDefs;
i: CARDINAL;
FOR i IN [1..LENGTH[map]) DO
GFT[map[i]] ← GFTItem[NullGlobalFrame, 0]; ENDLOOP;
END;
EnumerateCopies: PROCEDURE [
frame: GlobalFrameHandle,
proc: PROCEDURE [GlobalFrameHandle] RETURNS [BOOLEAN]]
RETURNS [result: GlobalFrameHandle, shared: BOOLEAN] =
BEGIN
FindCopies: PROCEDURE [f: GlobalFrameHandle] RETURNS [BOOLEAN] =
BEGIN
IF f = frame THEN RETURN[FALSE];
SELECT SameCode[frame, f] FROM
identical =>
BEGIN shared ← TRUE; IF f.copied AND proc[f] THEN RETURN[TRUE]; END;
same => shared ← TRUE;
ENDCASE;
RETURN[FALSE];
END;
shared ← FALSE;
IF ~frame.shared THEN RETURN[NIL, FALSE];
RETURN[FrameDefs.EnumerateGlobalFrames[FindCopies], shared];
END;
END...