-- UnNewConfig.mesa; edited by Geschke on September 7, 1978  3:29 PM

DIRECTORY
  BcdDefs: FROM "bcddefs" USING [MTHandle, MTIndex, UnboundLink],
  CodeDefs: FROM "codedefs" USING [CodeHandle],
  ControlDefs: FROM "controldefs" USING [
    ControlLink, FrameCodeBase, Free, GFT, GFTIndex, GFTItem,
    GlobalFrameHandle, NullGlobalFrame, TrapLink],
  FrameDefs: FROM "framedefs" USING [
    EnumerateGlobalFrames, GlobalFrame, LockCode, UnlockCode, UnNew],
  GlobalFrameDefs: FROM "globalframedefs" USING [GlobalFrameHandle],
  InlineDefs: FROM "inlinedefs" USING [BITAND],
  LoaderBcdUtilDefs: FROM "loaderbcdutildefs" USING [
    BcdBase, EnumerateModuleTable, ReleaseBcdSeg, SetUpBcd],
  LoaderDefs: FROM "loaderdefs",
  LoadStateDefs: FROM "loadstatedefs" USING [
    BcdAddress, BcdSegFromLoadState, ConfigIndex, EnumerateLoadStateBcds,
    InitializeRelocation, InputLoadState, MapRealToConfig, ReleaseLoadState,
    ReleaseRelocation, Relocation, RemoveConfig, SetUnresolvedImports],
  SegmentDefs: FROM "segmentdefs" USING [
    DeleteFileSegment, FileSegmentHandle, SwapError, SwapIn, SwapUp, Unlock],
  SystemDefs: FROM "systemdefs" USING [FreeSegment],
  XMesaDefs: FROM "xmesadefs" USING [LowHalfPtr, XCOPY, XFileSegmentAddress];

UnNewConfig: PROGRAM
  IMPORTS CodeDefs, FrameDefs, LoadStateDefs, LoaderBcdUtilDefs, SegmentDefs, SystemDefs, XMesaDefs
  EXPORTS LoaderDefs = BEGIN

  ConfigIndex: TYPE = LoadStateDefs.ConfigIndex;
  Relocation: TYPE = LoadStateDefs.Relocation;
  BcdBase: TYPE = LoaderBcdUtilDefs.BcdBase;
  GlobalFrameHandle: TYPE = ControlDefs.GlobalFrameHandle;
  NullGlobalFrame: GlobalFrameHandle = ControlDefs.NullGlobalFrame;

  UnNewConfig: PUBLIC PROCEDURE [frame: GlobalFrameHandle] =
    BEGIN OPEN LoadStateDefs;
    config: ConfigIndex;
    rel: Relocation;
    bcdseg: SegmentDefs.FileSegmentHandle;
    bcd: BcdBase;
    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];
    bcdseg ← BcdSegFromLoadState[config];
    bcd ← LoaderBcdUtilDefs.SetUpBcd[bcdseg];
    rel ← InitializeRelocation[config];
    UnBindConfig[config, bcd, rel];
    CleanupFrames[rel];
    CleanupGFT[rel];
    RemoveConfig[rel, config];
    ReleaseRelocation[rel];
    ReleaseLoadState[];
    LoaderBcdUtilDefs.ReleaseBcdSeg[bcdseg];
    RETURN
    END;
  
  CodeMatch: TYPE = {identical, same, different};

  SameCode: PROCEDURE [f1, f2: GlobalFrameHandle] RETURNS [CodeMatch] =
    BEGIN
    o1, o2: CARDINAL;
    fcb: ControlDefs.FrameCodeBase;
    seg1: SegmentDefs.FileSegmentHandle ← CodeDefs.CodeHandle[f1];
    seg2: SegmentDefs.FileSegmentHandle ← CodeDefs.CodeHandle[f2];
 
    IF seg1 # seg2 THEN RETURN[different];
    IF seg1.swappedin THEN
      BEGIN
      SegmentDefs.SwapIn[seg1];
      o1 ← LOOPHOLE[f1, GlobalFrameDefs.GlobalFrameHandle].code.shortCodebase -
		XMesaDefs.LowHalfPtr[XMesaDefs.XFileSegmentAddress[seg1]];
      SegmentDefs.Unlock[seg1];
      END
    ELSE
      BEGIN
      fcb ← f1.code;
      fcb.swappedout ← FALSE;
      o1 ← fcb.offset;
      END;
    IF seg2.swappedin THEN
      BEGIN
      SegmentDefs.SwapIn[seg2];
      o2 ← LOOPHOLE[f2, GlobalFrameDefs.GlobalFrameHandle].code.shortCodebase -
		XMesaDefs.LowHalfPtr[XMesaDefs.XFileSegmentAddress[seg2]];
      SegmentDefs.Unlock[seg2];
      END
    ELSE
      BEGIN
      fcb ← f2.code;
      fcb.swappedout ← FALSE;
      o2 ← fcb.offset;
      END;
    RETURN[IF o1 = o2 THEN identical ELSE same];
    END;

  CleanupFrames: PROCEDURE [rel: Relocation] =
    BEGIN
    frame: GlobalFrameHandle;
    i, ep: CARDINAL;
    nlinks: [0..256);
    alloced: BOOLEAN ← FALSE;
    DestroyCopy: PROCEDURE [f: GlobalFrameHandle] RETURNS [BOOLEAN] =
      BEGIN
      FrameDefs.UnNew[f];
      RETURN[FALSE];
      END;
    FOR i IN [1..LENGTH[rel]) DO
      [frame: frame, epbase: ep]  ← ControlDefs.GFT[rel[i]];
      IF frame = NullGlobalFrame OR ep # 0 THEN LOOP;
      IF frame.alloced THEN
	BEGIN
	FrameDefs.LockCode[frame];
	nlinks ← frame.code.prefix.nlinks;
	FrameDefs.UnlockCode[frame];
	END;
      IF ~EnumerateCopies[frame, DestroyCopy].shared THEN
	SegmentDefs.DeleteFileSegment[CodeDefs.CodeHandle[frame] !
	  SegmentDefs.SwapError => CONTINUE];
      IF frame.alloced THEN
	BEGIN
	Align: PROCEDURE [POINTER, WORD] RETURNS [POINTER] =
	  LOOPHOLE[InlineDefs.BITAND];
	IF frame.codelinks THEN ControlDefs.Free[frame]
	ELSE ControlDefs.Free[Align[frame - nlinks, 177774B]];
	alloced ← TRUE;
	END;
      ENDLOOP;
    IF ~alloced THEN SystemDefs.FreeSegment[frame];
    RETURN
    END;
  
  NextMultipleOfFour: PROCEDURE [n: UNSPECIFIED] RETURNS [UNSPECIFIED] =
    BEGIN
    RETURN[n+InlineDefs.BITAND[-n, 3B]]
    END;
  
  UnBindConfig: PROCEDURE [config: ConfigIndex, bcd: BcdBase, rel: Relocation] =
    BEGIN OPEN LoadStateDefs;
    bindeeRel: Relocation;
    nowUnresolved: BOOLEAN;
    UnBind: PROCEDURE [c: ConfigIndex, b: BcdAddress] RETURNS [BOOLEAN] =
      BEGIN
      bcdseg: SegmentDefs.FileSegmentHandle;
      bindee: BcdBase;
      IF c = config THEN RETURN[FALSE];
      bcdseg ← BcdSegFromLoadState[c];
      bindee ← LoaderBcdUtilDefs.SetUpBcd[bcdseg];
      IF bindee.nImports # 0 THEN
	BEGIN
	bindeeRel ← InitializeRelocation[c];
	nowUnresolved ← FALSE;
	[] ← LoaderBcdUtilDefs.EnumerateModuleTable[bindee, AdjustLinks];
	SetUnresolvedImports[c, nowUnresolved];
	ReleaseRelocation[bindeeRel];
	END;
      LoaderBcdUtilDefs.ReleaseBcdSeg[bcdseg];
      RETURN[FALSE]
      END;
    AdjustLinks: PROCEDURE [mth: BcdDefs.MTHandle, mti: BcdDefs.MTIndex]
      RETURNS [BOOLEAN] =
      BEGIN
      frame: GlobalFrameHandle = ControlDefs.GFT[bindeeRel[mth.gfi]].frame;
      nlinks: CARDINAL = mth.frame.length;
      changed: BOOLEAN;
      AdjustCopies: PROCEDURE [f: GlobalFrameHandle] RETURNS [BOOLEAN] =
	BEGIN
	[] ← AdjustFrame[f, mth.code.offset, nlinks];
	RETURN[FALSE];
	END;
      IF frame = NullGlobalFrame OR nlinks = 0 THEN RETURN[FALSE];
      changed ← AdjustFrame[frame, mth.code.offset, nlinks];
      IF changed AND frame.shared AND ~frame.codelinks THEN
	[] ← EnumerateCopies[frame, AdjustCopies];
      IF changed THEN nowUnresolved ← TRUE;
      RETURN[FALSE]
      END;
    AdjustFrame: PROCEDURE [frame: GlobalFrameHandle, offset, nlinks: CARDINAL]
      RETURNS [changed: BOOLEAN] =
      BEGIN
      seg: SegmentDefs.FileSegmentHandle = CodeDefs.CodeHandle[frame];
      linkbase: LONG POINTER TO ControlDefs.ControlLink;
      i: CARDINAL;
      changed ← FALSE;
      IF frame.codelinks THEN
	BEGIN OPEN SegmentDefs;
	SwapIn[seg];
	linkbase ← XMesaDefs.XFileSegmentAddress[seg] + offset;
	END
      ELSE linkbase ← LONG[LOOPHOLE[frame, POINTER TO ControlDefs.ControlLink]];
      FOR i IN [1..nlinks] DO
	BEGIN OPEN ControlDefs;
	link: ControlLink;
	XMesaDefs.XCOPY[to: LONG[@link], from: linkbase-i, nwords: SIZE[ControlLink]];
	IF BoundHere[link] THEN
	  BEGIN
	  tlink: ControlLink ← (SELECT link.tag FROM
	    frame => TrapLink, ENDCASE => BcdDefs.UnboundLink);
	  XMesaDefs.XCOPY[from: LONG[@tlink], to: linkbase-i, nwords: SIZE[ControlLink]];
	  changed ← TRUE;
	  END;
	END;
	ENDLOOP;
      IF frame.codelinks THEN
	BEGIN OPEN SegmentDefs;
	IF changed THEN
	  BEGIN seg.write ← TRUE; SwapUp[seg]; seg.write ← FALSE; END;
	Unlock[seg];
	END;
      RETURN
      END;
    BoundHere: PROCEDURE [link: ControlDefs.ControlLink] RETURNS [BOOLEAN] =
      BEGIN
      i: CARDINAL;
      gfi: ControlDefs.GFTIndex;
      SELECT link.tag FROM
	unbound => RETURN[FALSE];
	ENDCASE => gfi ← FrameDefs.GlobalFrame[link].gfi;
      FOR i IN [0..LENGTH[rel]) DO
	IF rel[i] = gfi THEN RETURN[TRUE];
	ENDLOOP;
      RETURN[FALSE];
      END;
  
    IF bcd.nExports = 0 AND bcd.nModules # 1 THEN RETURN;
    [] ← EnumerateLoadStateBcds[recentfirst, UnBind];
    RETURN
    END;
  
  CleanupGFT: PROCEDURE [rel: Relocation] =
    BEGIN OPEN ControlDefs;
    i: CARDINAL;
    FOR i IN [1..LENGTH[rel]) DO
      GFT[rel[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;
    RETURN[FrameDefs.EnumerateGlobalFrames[FindCopies], shared];
    END;

END...