<> <> <> <> <> <> <> <<>> DIRECTORY Atom USING [GetPName, GetProp, MakeAtom], BcdDefs USING [ProcLimit, FTSelf, IMPIndex, Link, MTIndex, MTRecord, UnboundLink, VersionStamp, BcdBase, IMPHandle, MTHandle, NameString], BcdOps USING [ProcessImports, ProcessModules], IO USING [STREAM, ROS, PutChar, RopeFromROS], Loader USING [IRList], LoaderOps USING [IsNullLink, PendingModule, Binding, IR, Pending, FindVariableLink, GetPendingList, SetPendingList, BindingSequence, GetIR], LoadState USING [ConfigInfo, ConfigID, ModuleInfo, local, EnumerateConfigs, BuildProcDescUsingModule], PrincOps USING [ControlLink, GlobalFrameHandle, NullLink, UnboundLink], PrincOpsUtils USING [Codebase], Rope USING [Text, Length, InlineFetch], Table USING [Base], VM USING [Interval, MakeReadOnly, MakeReadWrite, PageNumberForAddress, Age]; CedarLinkerImpl: PROGRAM IMPORTS Atom, BcdOps, IO, LoaderOps, LoadState, PrincOpsUtils, Rope, VM EXPORTS LoaderOps = { OPEN BcdDefs, Loader, LoaderOps; pendingCount: INT _ 0; pendingModules: PUBLIC LIST OF PendingModule; <> <<********************************************************************>> <> <> <<********************************************************************>> Bind: PUBLIC PROC[config: LoadState.ConfigID] RETURNS[unboundImports: IRList _ NIL] = { bcd: BcdBase = LoadState.local.ConfigInfo[config].bcd; binding: Binding; BindModule: PROC[mth: MTHandle, mti: MTIndex] RETURNS[stop: BOOL _ FALSE] = { frame: PrincOps.GlobalFrameHandle = LoadState.local.ModuleInfo[config, mth.gfi].gfh; IF frame = NIL THEN RETURN; -- StartCedarCore disappears, for example <> OpenLinkSpace[frame, mth, bcd]; <> FOR i: NAT IN [0..LinkSegmentLength[mth, bcd]) DO index: NAT; interface: IR; atom: ATOM; name: Rope.Text; bcdLink: Link; link: PrincOps.ControlLink; pending: LIST OF Pending; bcdLink _ IthLink[mth, i, bcd]; <> IF ~test THEN SELECT bcdLink.vtag FROM var, type => WriteLink[i, PrincOps.NullLink]; proc0, proc1 => WriteLink[i, PrincOps.UnboundLink]; ENDCASE => ERROR; <> IF bcdLink.gfi < bcd.firstdummy THEN { <> link _ SELECT bcdLink.vtag FROM var => FindVariableLink[config, bcdLink.gfi, bcdLink].link, proc0, proc1 => IF bcdLink = BcdDefs.UnboundLink THEN PrincOps.UnboundLink -- the binder couldn't bind it. ELSE LoadState.local.BuildProcDescUsingModule[config, bcdLink.gfi, bcdLink.ep], <> type => PrincOps.NullLink, ENDCASE => ERROR; WriteLink[i, link]; LOOP}; <> IF bcdLink.vtag # proc0 AND bcdLink.vtag # proc1 THEN ERROR; atom _ binding[bcdLink.gfi].atom; name _ Atom.GetPName[atom]; pending _ GetPendingList[atom]; interface _ binding[bcdLink.gfi].interface; IF interface = NIL THEN { -- imported module (rare) version: VersionStamp; link _ GetModuleLink[atom]; IF test OR ~IsNullLink[link] THEN {WriteLink[i, link]; LOOP}; <> unboundImports _ CONS[[name, 0], unboundImports]; version _ NARROW[Atom.GetProp[atom, $version], REF VersionStamp]^; pendingModules _ CONS[[frame, mth, bcd, i, name, version], pendingModules]; LOOP}; <> index _ bcdLink.ep + (binding[bcdLink.gfi].whichgfi*ProcLimit); link _ interface[index]; IF test OR ~IsNullLink[link] THEN {WriteLink[i, link]; LOOP}; <> unboundImports _ CONS[[name, index], unboundImports]; --resolved _ FALSE; <> pendingCount _ pendingCount + 1; pending _ CONS[[frame, mth, bcd, i, LOOPHOLE[index]], pending]; SetPendingList[atom, pending]; ENDLOOP; <> DeactivateLinkSpace[frame]; }; -- BindModule <> binding _ GetBinding[bcd]; -- binds dummy gfi's to IR's [] _ BcdOps.ProcessModules[bcd, BindModule]; -- fill in the links areas MakeLinksReadOnly[bcd, config]; -- done all at once for efficiency. }; -- Bind <> GetModuleLink: PUBLIC PROC[atom: ATOM] RETURNS[link: PrincOps.ControlLink _ PrincOps.NullLink] = { <> <> name: Rope.Text _ Atom.GetPName[atom]; version: VersionStamp _ NARROW[Atom.GetProp[atom, $version], REF VersionStamp]^; Find: PROC[config: LoadState.ConfigID] RETURNS[stop: BOOL] = { bcd: BcdBase _ LoadState.local.ConfigInfo[config].bcd; ftb: Table.Base = LOOPHOLE[bcd + bcd.ftOffset]; ssb: NameString = LOOPHOLE[bcd + bcd.ssOffset]; FindModule: PROC[mth: MTHandle, mti: MTIndex] RETURNS[stop: BOOL _ FALSE] = { IF mth.file = FTSelf THEN IF bcd.version # version THEN RETURN ELSE NULL ELSE IF ftb[mth.file].version # version THEN RETURN; <<>> <> IF ssb.size[mth.name] # Rope.Length[name] THEN RETURN; FOR i: NAT IN [0..ssb.size[mth.name]) DO IF Rope.InlineFetch[name, i] # ssb.string.text[mth.name+i] THEN RETURN; ENDLOOP; <<>> <> <> link _ LOOPHOLE[LoadState.local.ModuleInfo[config, mth.gfi].gfh]; <> RETURN[stop: TRUE]; }; -- end FindModule <> [] _ BcdOps.ProcessModules[bcd, FindModule]; RETURN[link # PrincOps.NullLink]; }; -- end Find <<>> <> [] _ LoadState.local.EnumerateConfigs[newestFirst, Find]; }; MakeLinksReadOnly: PROC[bcd: BcdBase, config: LoadState.ConfigID] = { MakeReadOnly: PROC[mth: MTHandle, mti: MTIndex] RETURNS[stop: BOOL _ FALSE] = { frame: PrincOps.GlobalFrameHandle = LoadState.local.ModuleInfo[config, mth.gfi].gfh; IF frame # NIL AND frame.codelinks THEN VM.MakeReadOnly[GetCodeLinksInterval[frame, mth, bcd].interval]; }; [] _ BcdOps.ProcessModules[bcd, MakeReadOnly]; }; <<>> <<********************************************************************>> <> <> <> <> <<********************************************************************>> GetBinding: PUBLIC PROC[bcd: BcdBase] RETURNS[binding: Binding] = { <> ftb: Table.Base = LOOPHOLE[bcd + bcd.ftOffset]; ssb: NameString = LOOPHOLE[bcd + bcd.ssOffset]; BindImport: PROC[imph: IMPHandle, impi: IMPIndex] RETURNS[stop: BOOL _ FALSE] = { size: NAT; interface: IR; atom: ATOM; <<>> <> s: IO.STREAM = IO.ROS[]; FOR i: NAT IN [0..ssb.size[imph.name]) DO s.PutChar[ssb.string.text[imph.name+i]] ENDLOOP; atom _ Atom.MakeAtom[s.RopeFromROS[]]; size _ IF imph.port = module THEN 0 ELSE imph.ngfi*ProcLimit; interface _ GetIR[atom, ftb[imph.file].version, size].interface; FOR i: NAT IN [0..imph.ngfi) DO binding[imph.gfi + i] _ [whichgfi: i, atom: atom, interface: interface]; ENDLOOP; }; binding _ NEW[BindingSequence[bcd.firstdummy+bcd.nDummies]]; [] _ BcdOps.ProcessImports[bcd, BindImport]; }; <<>> <<********************************************************************>> <> <<********************************************************************>> linkSpace: VM.Interval; -- used if codelinks. Should enclose links area. set RO by CloseLinkSpace. codelinks: BOOL; writeable: BOOL; links: LinksPtr; LinksPtr: TYPE = LONG POINTER TO LinksRec; LinksRec: TYPE = RECORD[SEQUENCE COMPUTED NAT OF PrincOps.ControlLink]; GetCodeLinksInterval: PROC [frame: PrincOps.GlobalFrameHandle, mth: MTHandle, bcd: BcdBase] RETURNS [links: LinksPtr, interval: VM.Interval] = { linkSegmentLength: CARDINAL = LinkSegmentLength[mth, bcd]; p1, p2: INT; links _ LOOPHOLE[PrincOpsUtils.Codebase[frame], LinksPtr] - linkSegmentLength; p1 _ VM.PageNumberForAddress[links]; p2 _ VM.PageNumberForAddress[links + linkSegmentLength - 1]; interval _ [page: p1, count: p2-p1+1]; }; OpenLinkSpace: PUBLIC PROC [frame: PrincOps.GlobalFrameHandle, mth: MTHandle, bcd: BcdBase] = { linkSegmentLength: CARDINAL = LinkSegmentLength[mth, bcd]; codelinks _ frame.codelinks; IF codelinks THEN [links, linkSpace] _ GetCodeLinksInterval[frame, mth, bcd] ELSE links _ LOOPHOLE[LONG[frame], LinksPtr] - linkSegmentLength; writeable _ FALSE; -- current links area stays readOnly as long as possible }; LinkSegmentLength: PUBLIC PROC[mth: MTHandle, bcd: BcdBase] RETURNS[CARDINAL] = { WITH mth: mth SELECT FROM direct => RETURN[mth.length]; indirect => RETURN[LOOPHOLE[bcd + bcd.lfOffset, Table.Base][mth.links].length]; multiple => RETURN[LOOPHOLE[bcd + bcd.lfOffset, Table.Base][mth.links].length]; ENDCASE => ERROR; }; IthLink: PUBLIC PROC[mth: MTHandle, i: CARDINAL, bcd: BcdBase] RETURNS[Link] = { WITH mth: mth SELECT FROM direct => RETURN[mth.frag[i]]; indirect => RETURN[LOOPHOLE[bcd + bcd.lfOffset, Table.Base][mth.links].frag[i]]; multiple => RETURN[LOOPHOLE[bcd + bcd.lfOffset, Table.Base][mth.links].frag[i]]; ENDCASE => ERROR; }; WriteLink: PUBLIC PROC [offset: CARDINAL, link: PrincOps.ControlLink] = { IF skipWrites THEN RETURN; IF test THEN { oldLink: PrincOps.ControlLink _ ReadLink[offset]; IF IsNullLink[oldLink] AND IsNullLink[link] THEN RETURN; IF oldLink # link THEN errors _ errors + 1; RETURN}; IF codelinks AND ~writeable THEN { <> writeable _ TRUE; VM.MakeReadWrite[linkSpace]; }; links[offset] _ link; }; ReadLink: PUBLIC PROC [offset: CARDINAL] RETURNS [link: PrincOps.ControlLink] = { RETURN[links[offset]]; }; DeactivateLinkSpace: PROC[frame: PrincOps.GlobalFrameHandle] = { IF frame.codelinks AND writeable THEN VM.Age[linkSpace]; }; CloseLinkSpace: PUBLIC PROC [frame: PrincOps.GlobalFrameHandle] = { IF frame.codelinks AND writeable THEN VM.MakeReadOnly[linkSpace]; }; <<>> <<********************************************************************>> <> <<********************************************************************>> errors: INT; test, skipWrites: BOOL _ FALSE; <> <> <> <> <<[] _ Bind[cid];>> <<};>> <> <> <> <<[] _ LoadState.local.EnumerateConfigs[order: oldestFirst, proc: proc];>> <> <> <> <<};>> <> <> <> <> <> <<[cm, ] _ Instantiate[file: cap, offset: 1, codeLinks: TRUE];>> <> <> <<[] _ Enumerate[skip: TRUE]; was used to initialize pending items; 5.0 bootfiles have no imports>> } . . .