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; } . . . ˆCedarLinkerImpl.mesa - fills in the links of a newly loaded bcd. Copyright c 1985 by Xerox Corporation. All rights reserved. Maxwell on: February 28, 1983 1:45 pm Levin, August 9, 1983 11:46 am Rovner on: August 15, 1983 11:57 am MBrown on: September 11, 1983 12:53 pm Russ Atkinson (RRA) February 4, 1985 4:42:53 pm PST list of people waiting for a MODULE to be exported ******************************************************************** Bind: Creates a binding between the dummy imports and actual interfaces, and then fills in the links area of each module in the bcd. ******************************************************************** open the link space (only done once per module) import each element of the fragment initialize link is the link imported from within the bcd? rgfi: PrincOps.GFTIndex = LoadState.local.ModuleInfo[config, bcdLink.gfi].gfh.gfi; WAS [procedure[gfi: rgfi, ep: bcdLink.ep, tag: TRUE]], imports an interface or a module outside of the bcd module hasn't been loaded yet. Put it on the list. interface # NIL entry hasn't been exported yet. Put it on the interface's pending list. pending _ GetPendingList[atom]; all done, deactivate links area START Bind HERE GetModuleLink: Whizzes thru the loadstate, looking at each module in each BCD, asking whether its name and version stamp match atom's PName and atom's $version property value (a REF VersionStamp), respectively. ASSUMES that the $version property exists for atom. If the desired module is found, GetModuleLink returns its GFH as a PrincOps.ControlLink. If not, GetModuleLink returns PrincOps.NullLink. whiz through the load state looking for this module this is an expensive procedure! Here if this module version matches the one associated as $version with atom Here if this module's name matches atom's PName: get the module's GFH, assign it to "link" link is a GFH in this case START Find HERE START GetModuleLink HERE ******************************************************************** A Binding is a mapping between the dummy gfi's within the bcd and real interfaces. The dummy gfi's are a coding trick to simulate interfaces. There are bcd.nDummies gfi's starting at bcd.firstdummy. There can be more than one dummy gfi for an interface since there can be at most 16 entries per gfi slot. ******************************************************************** create a binding between dummy gfi's and interfaces get the name of the interface ******************************************************************** procedures that manipulate the links area. ******************************************************************** make the (code) links area writable (this is the first WriteLink after OpenLinkSpace) ******************************************************************** testing and initialization ******************************************************************** Test: PROC RETURNS[totalErrors: INT] = {RETURN[Enumerate[skip: FALSE]]}; Enumerate: PROC[skip: BOOL] RETURNS[totalErrors: INT] = { proc: PROC [cid: ConfigID] RETURNS [stop: BOOL _ FALSE] = { IF skip AND ~BcdUnresolved[cid] THEN RETURN; [] _ Bind[cid]; }; LoadState.local.Acquire[exclusive]; errors _ 0; IF skip THEN skipWrites _ TRUE ELSE test _ TRUE; [] _ LoadState.local.EnumerateConfigs[order: oldestFirst, proc: proc]; LoadState.local.Release[]; IF skip THEN skipWrites _ FALSE ELSE test _ FALSE; RETURN[errors]; }; TestLoad: PROC[file: LONG STRING] = BEGIN cap: File.Capability; cm: PrincOps.ControlModule; cap _ Directory.Lookup[file]; [cm, ] _ Instantiate[file: cap, offset: 1, codeLinks: TRUE]; Start[cm]; END; [] _ Enumerate[skip: TRUE]; was used to initialize pending items; 5.0 bootfiles have no imports Κ n˜codešœ@™@Kšœ Οmœ1™Kšœ6˜6Kšœžœ˜/Kšœžœ˜/š Ÿ œžœžœžœžœ˜Mšžœ˜Kš žœžœžœžœžœžœ˜4Kšžœžœ!žœžœ˜4—K™KšœL™LKšžœ(žœžœ˜6šžœžœžœž˜(Kšžœ9žœžœ˜GKšžœ˜—K™šœ0™0Kšœ)™)—šœžœ2˜AKšœ™—Kšžœžœ˜Kšœ ˜—Kšœ™K˜,Kšžœ˜!Kšœ  ˜—K™Kšœ™Kšœ9˜9Kšœ˜K˜—šŸœžœ.˜Eš Ÿ œžœžœžœžœ˜OKšœT˜Tšžœ žœžœ˜"Kšžœžœ>˜E—Kšœ˜—K˜.Kšœ˜K˜—K™KšœD™DKšœR™RKšœR™RKšœX™XKšœ3™3KšœD™DK˜šŸ œžœžœžœ˜CKšœ3™3Kšœžœ˜/Kšœžœ˜/š Ÿ œžœ"žœžœžœ˜QKšœžœ˜ Kšœ žœ˜Kšœžœ˜ K™Kšœ™Kš œžœžœžœžœ˜Kš žœžœžœžœ)žœ˜ZKšœ&˜&Kšœžœžœžœ˜=K˜@šžœžœžœž˜K˜HKšžœ˜—Kšœ˜—Kšœ žœ1˜>K˜,Kšœ˜K˜—K™KšœD™DKšœ*™*KšœD™DK˜Kšœ žœ  J˜bKšœ žœ˜Kšœ žœ˜šœ˜Kš œ žœžœžœžœ ˜*Kš œ žœžœžœžœžœžœ˜G—K˜šŸœžœAž œžœ˜Kšœžœ˜:Kšœžœ˜ Kšœžœ>˜NKšœžœ˜$Kšœžœ5˜