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 [IRItem], 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 = BEGIN OPEN BcdDefs, LoaderOps; pendingCount: INT _ 0; pendingModules: PUBLIC LIST OF PendingModule; Bind: PUBLIC PROC[config: LoadState.ConfigID] RETURNS[unboundImports: LIST OF Loader.IRItem _ NIL] = BEGIN bcd: BcdBase = LoadState.local.ConfigInfo[config].bcd; binding: Binding; BindModule: PROC[mth: MTHandle, mti: MTIndex] RETURNS[stop: BOOL _ FALSE] = BEGIN 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]; END; -- 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. END; -- Bind GetModuleLink: PUBLIC PROC[atom: ATOM] RETURNS[link: PrincOps.ControlLink _ PrincOps.NullLink] = BEGIN -- whiz through the load state looking for this module 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]; END; 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] = BEGIN -- create a binding between dummy gfi's and interfaces ftb: Table.Base = LOOPHOLE[bcd + bcd.ftOffset]; ssb: NameString = LOOPHOLE[bcd + bcd.ssOffset]; BindImport: PROC[imph: IMPHandle, impi: IMPIndex] RETURNS[stop: BOOL _ FALSE] = BEGIN 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; END; binding _ NEW[BindingSequence[bcd.firstdummy+bcd.nDummies]]; [] _ BcdOps.ProcessImports[bcd, BindImport]; END; linkSpace: VM.Interval; -- used if codelinks. Should enclose links area. set RO by CloseLinkSpace. codelinks: BOOL; writeable: BOOL; links: LONG POINTER TO ARRAY [0..0) OF PrincOps.ControlLink; GetCodeLinksInterval: PROC [frame: PrincOps.GlobalFrameHandle, mth: MTHandle, bcd: BcdBase] RETURNS[links: LONG POINTER TO ARRAY [0..0) OF PrincOps.ControlLink, interval: VM.Interval] = { linkSegmentLength: CARDINAL = LinkSegmentLength[mth, bcd]; p1, p2: INT; links _ PrincOpsUtils.Codebase[LOOPHOLE[frame]] - 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], LONG POINTER TO ARRAY [0..0) OF PrincOps.ControlLink] - 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; END . . . CedarLinkerImpl.mesa fills in the links of a newly loaded bcd. Last edited by: John Maxwell on: February 28, 1983 1:45 pm Last Edited by: Levin, August 9, 1983 11:46 am Last edited by: Paul Rovner on: August 15, 1983 11:57 am Last edited by: MBrown on: September 11, 1983 12:53 pm 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. 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. ******************************************************************** 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, ] _ Loader.Instantiate[file: cap, offset: 1, codeLinks: TRUE]; Loader.Start[cm]; END; [] _ Enumerate[skip: TRUE]; was used to initialize pending items; 5.0 bootfiles have no imports Ê É˜Jšœ™Jšœ)™)Jšœ:™:J™.Jšœ8™8Jšœ6™6šÏk ˜ Jšœœ˜)šœœ˜J˜{—Jšœœ"˜.Jš œœœœœ ˜-Jšœœ ˜Jšœ œ&œU˜Œšœ œ˜JšœU˜U—šœ œ˜Jšœ7˜7—Jšœœ ˜Jšœœ˜'Jšœœ˜JšœœD˜LJ˜—Jšœ˜Jšœœ+˜GJšœ ˜J˜Jšœ œœ˜"J˜Jšœœ˜Jšœœœœ˜-Jšœ2™2J˜JšœD™DJšœN™NJšœ9™9JšœD™DJ˜šÏnœœœ˜/Jšœœœœ˜6Jš˜Jšœ6˜6J˜š ž œœœœœ˜KJš˜JšœT˜TJš œ œœœÏc)˜EJšœ/™/J˜Jšœ#™#šœœœ"˜1Jšœœ˜ Jšœ œ˜Jšœœ˜ J˜J˜J˜Jšœ œœ ˜J˜Jšœ™šœœœ˜&J˜-J˜3Jšœœ˜—Jšœ)™)šœœ˜'JšœR™Ršœœ˜Jšœ;˜;šœ˜Jšœ˜ JšœŸ˜9šœK˜OJšœ6™6——J˜Jšœœ˜—J˜Jšœ˜—Jšœ3™3Jšœœœœ˜Jšœ6˜6Jšœœ˜/Jšœœ˜/š ž œœœœœ˜Mšœ˜Jš œœœœœœ˜4Jšœœ!œœ˜4—J™JšœL™LJšœ(œœ˜6šœœœ˜(Jšœ9œœ˜GJšœ˜—J™šœ0™0Jšœ)™)—šœœ2˜AJšœ™—Jšœœ˜JšœŸ˜—Jšœ™J˜,Jšœ˜!JšœŸ ˜—J™Jšœ™Jšœ9˜9Jšœ˜J˜—šžœœ.˜Eš ž œœœœœ˜OJšœT˜Tšœ œœ˜"Jšœœ>˜E—Jšœ˜—J˜.Jšœ˜J˜—J™JšœD™DJšœR™RJšœR™RJšœX™XJšœ3™3JšœD™DJ˜šž œœœœ˜AJšœŸ6˜J˜,Jšœ˜J˜—J™JšœD™DJšœ*™*JšœD™DJ˜Jšœ œ ŸJ˜bJšœ œ˜Jšœ œ˜Jš œœœœœœ˜Jšœ˜šœœ œ˜Jšœ œ˜!Jšœ œœ5˜QJšœ œœ5˜QJšœœ˜J˜——šž œœœ œ!˜IJšœ œœ˜šœœ˜J˜1Jšœœœœ˜8Jšœœ˜+Jšœ˜ —šœ œ ˜šœ˜JšœU™UJšœ œ˜Jšœ˜Jšœ˜——J˜J˜J˜—š žœœœ œœ˜OJšœœ˜J˜—šžœœ'˜@Jšœœ œœ˜:J˜—šžœœœ(˜CJšœœ œœ˜BJ˜—J™JšœD™DJšœ™JšœD™DJ˜Jšœœ˜ Jšœœœ˜J˜šœH™HJ˜—šœ9™9šœ;™;Jšœ,™,Jšœ™Jšœ™—Jšœ#™#Jšœ ™ Jšœ0™0JšœF™FJšœ™Jšœ2™2Jšœ™Jšœ™J˜—šœ#™#Jšœ™Jšœ™Jšœ™Jšœ™JšœC™CJšœ™Jšœ™—J˜Jšœ`™`J˜Jšœ˜ J˜˜J˜——…— Î:›