DIRECTORY Atom USING [GetPName, GetProp], AtomsPrivate USING [UnsafeMakeAtom], BcdDefs USING [ EPLimit, FTSelf, IMPIndex, Link, MTIndex, MTRecord, UnboundLink, VersionStamp], BcdOps USING [ BcdBase, IMPHandle, MTHandle, NameString, ProcessImports, ProcessModules], CedarLinkerOps, Directory USING [Lookup], File USING [Capability, write], Loader USING [Instantiate, Start, Error], LoaderPrivate USING [FindMappedSpace], RuntimeInternal USING [Codebase], PilotLoaderOps USING [], PilotLoadStateOps USING [ AcquireBcd, BcdUnresolved, ConfigIndex, EnumerateBcds, GetMap, InputLoadState, Map, MapConfigToReal, ReleaseBcd, ReleaseLoadState, ReleaseMap], PrincOps USING [ ControlLink, ControlModule, GFTIndex, GlobalFrameHandle, NullLink, UnboundLink], PrincOpsRuntime USING [GetFrame, GFT], Rope USING [Text], Space USING [ Deactivate, GetHandle, GetWindow, Handle, MakeReadOnly, MakeWritable, PageFromLongPointer], Table USING [Base]; CedarLinkerImpl: PROGRAM IMPORTS Atom, AtomsPrivate, BcdOps, CedarLinkerOps, Directory, Loader, LoaderPrivate, RuntimeInternal, PilotLoadStateOps, PrincOpsRuntime, Space EXPORTS CedarLinkerOps, LoaderPrivate, PilotLoaderOps SHARES File, Rope = BEGIN OPEN BcdDefs, BcdOps, CedarLinkerOps; pendingCount: INT _ 0; pendingModules: PUBLIC LIST OF PendingModule; Bind: PUBLIC PROC[bcd: BcdBase, map: PilotLoadStateOps.Map] RETURNS[resolved: BOOLEAN _ TRUE] = BEGIN binding: Binding; BindModule: PROC[mth: MTHandle, mti: MTIndex] RETURNS[stop: BOOLEAN _ FALSE] = BEGIN frame: PrincOps.GlobalFrameHandle; frame _ PrincOpsRuntime.GetFrame[PrincOpsRuntime.GFT[map[mth.gfi]]]; IF frame = NIL THEN RETURN; -- StartCedarCore disappears OpenLinkSpace[frame, mth, bcd]; FOR i: NAT IN [0..LinkSegmentLength[mth, bcd]) DO index: NAT; interface: IR; atom: ATOM; name: Rope.Text; bcdLink: BcdDefs.Link; rgfi: PrincOps.GFTIndex; 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 { rgfi _ map[bcdLink.gfi]; link _ SELECT bcdLink.vtag FROM var => FindVariableLink[bcd, bcdLink, rgfi].link, proc0, proc1 => IF bcdLink = BcdDefs.UnboundLink THEN PrincOps.UnboundLink -- the binder couldn't bind it. ELSE [procedure[gfi: rgfi, ep: bcdLink.ep, tag: TRUE]], 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: BcdDefs.VersionStamp; link _ GetModuleLink[atom]; IF test OR ~NullLink[link] THEN {WriteLink[i, link]; LOOP}; resolved _ FALSE; 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*EPLimit); link _ interface[index]; IF test OR ~NullLink[link] THEN {WriteLink[i, link]; LOOP}; resolved _ FALSE; pendingCount _ pendingCount + 1; pending _ CONS[[frame, mth, bcd, i, LOOPHOLE[index]], pending]; SetPendingList[atom, pending]; ENDLOOP; DeactivateLinkSpace[frame]; END; binding _ GetBinding[bcd]; -- binds dummy gfi's to IR's [] _ BcdOps.ProcessModules[bcd, BindModule]; -- fill in the links areas MakeLinksReadOnly[bcd, map]; -- done all at once for efficiency. END; GetModuleLink: PUBLIC PROC[atom: ATOM] RETURNS[link: PrincOps.ControlLink _ PrincOps.NullLink] = BEGIN -- whiz through the load state looking for this module rgfi: PrincOps.GFTIndex _ 0; name: Rope.Text _ Atom.GetPName[atom]; version: VersionStamp _ NARROW[Atom.GetProp[atom, $version], REF VersionStamp]^; Find: PROC[config: PilotLoadStateOps.ConfigIndex] RETURNS[BOOLEAN] = BEGIN bcd: BcdBase _ PilotLoadStateOps.AcquireBcd[config]; ftb: Table.Base = LOOPHOLE[bcd + bcd.ftOffset]; ssb: BcdOps.NameString = LOOPHOLE[bcd + bcd.ssOffset]; FindModule: PROC[mth: MTHandle, mti: MTIndex] RETURNS[stop: BOOLEAN _ FALSE] = BEGIN IF mth.file = BcdDefs.FTSelf THEN IF bcd.version # version THEN RETURN ELSE NULL ELSE IF ftb[mth.file].version # version THEN RETURN; IF ssb.size[mth.name] # name.length THEN RETURN; FOR i: NAT IN [0..ssb.size[mth.name]) DO IF name.text[i] # ssb.string.text[mth.name+i] THEN RETURN; ENDLOOP; rgfi _ PilotLoadStateOps.MapConfigToReal[mth.gfi, config]; link _ LOOPHOLE[PrincOpsRuntime.GetFrame[PrincOpsRuntime.GFT[rgfi]]]; RETURN[stop: TRUE]; END; [] _ BcdOps.ProcessModules[bcd, FindModule]; PilotLoadStateOps.ReleaseBcd[bcd]; RETURN[rgfi # 0]; END; [] _ PilotLoadStateOps.EnumerateBcds[recentfirst, Find]; END; MakeLinksReadOnly: PROC[bcd: BcdBase, map: PilotLoadStateOps.Map] = BEGIN MakeReadOnly: PROC[mth: MTHandle, mti: MTIndex] RETURNS[stop: BOOLEAN _ FALSE] = BEGIN frame: PrincOps.GlobalFrameHandle; frame _ PrincOpsRuntime.GetFrame[PrincOpsRuntime.GFT[map[mth.gfi]]]; IF frame # NIL AND frame.codelinks THEN { lp: LONG POINTER _ RuntimeInternal.Codebase[LOOPHOLE[frame]]; space: Space.Handle _ Space.GetHandle[Space.PageFromLongPointer[lp]]; Space.MakeReadOnly[space]}; END; [] _ BcdOps.ProcessModules[bcd, MakeReadOnly]; END; GetBinding: PUBLIC PROC[bcd: BcdBase] RETURNS[binding: Binding] = BEGIN -- create a binding between dummy gfi's and interfaces maxInterfaceNameLength: NAT = 40; name: STRING = [maxInterfaceNameLength]; ftb: Table.Base = LOOPHOLE[bcd + bcd.ftOffset]; ssb: BcdOps.NameString = LOOPHOLE[bcd + bcd.ssOffset]; BindImport: PROC[imph: IMPHandle, impi: IMPIndex] RETURNS[stop: BOOLEAN _ FALSE] = BEGIN size: NAT; interface: IR; atom: ATOM; name.length _ 0; FOR i: NAT IN [0..ssb.size[imph.name]) DO m: STRING = "interface name too long"; IF name.length = maxInterfaceNameLength THEN ERROR Loader.Error[type: invalidBcd, message: LOOPHOLE[LONG[m]]]; name[name.length] _ ssb.string.text[imph.name+i]; name.length _ name.length+1; ENDLOOP; size _ IF imph.port = module THEN 0 ELSE imph.ngfi*EPLimit; atom _ AtomsPrivate.UnsafeMakeAtom[LOOPHOLE[LONG[name]]]; 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: Space.Handle; long, writeable: BOOLEAN; links: LONG POINTER TO ARRAY [0..0) OF PrincOps.ControlLink; OpenLinkSpace: PUBLIC PROC [frame: PrincOps.GlobalFrameHandle, mth: BcdOps.MTHandle, bcd: BcdBase _ NIL] = {IF frame.codelinks THEN { long _ TRUE; links _ RuntimeInternal.Codebase[LOOPHOLE[frame]]} ELSE {long _ FALSE; links _ LOOPHOLE[LONG[frame]]}; links _ links - LinkSegmentLength[mth, bcd]; writeable _ FALSE}; LinkSegmentLength: PUBLIC PROC[mth: BcdOps.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: BcdOps.MTHandle, i: CARDINAL, bcd: BcdBase] RETURNS[BcdDefs.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 NullLink[oldLink] AND NullLink[link] THEN RETURN; IF oldLink # link THEN errors _ errors + 1; RETURN}; IF long AND ~writeable THEN {cap: File.Capability; writeable _ TRUE; linkSpace _ Space.GetHandle[Space.PageFromLongPointer[links]]; cap _ Space.GetWindow[LoaderPrivate.FindMappedSpace[linkSpace]].file; cap.permissions _ cap.permissions + File.write; Space.MakeWritable[linkSpace, cap]}; links[offset] _ link}; ReadLink: PUBLIC PROC [offset: CARDINAL] RETURNS [link: PrincOps.ControlLink] = {RETURN[links[offset]]}; DeactivateLinkSpace: PROC[frame: PrincOps.GlobalFrameHandle] = { IF long AND writeable THEN Space.Deactivate[linkSpace]}; CloseLinkSpace: PUBLIC PROC [frame: PrincOps.GlobalFrameHandle] = { IF long AND writeable THEN Space.MakeReadOnly[linkSpace]}; errors: INT; test, skipWrites: BOOLEAN _ FALSE; Test: PROC RETURNS[totalErrors: INT] = {RETURN[Enumerate[skip: FALSE]]}; Enumerate: PROC[skip: BOOLEAN] RETURNS[totalErrors: INT] = BEGIN OPEN PilotLoadStateOps; map: Map; bcd: BcdBase; nbcds: ConfigIndex _ InputLoadState[]; errors _ 0; IF skip THEN skipWrites _ TRUE ELSE test _ TRUE; FOR i: ConfigIndex IN [0..nbcds) DO IF skip AND ~BcdUnresolved[i] THEN LOOP; bcd _ AcquireBcd[i]; map _ GetMap[i]; [] _ Bind[bcd, map]; ReleaseBcd[bcd]; ReleaseMap[map]; ENDLOOP; ReleaseLoadState[]; IF skip THEN skipWrites _ FALSE ELSE test _ FALSE; RETURN[errors]; END; 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]; -- initializes pending items 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: Paul Rovner on: December 8, 1982 9:30 am 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. 'map' maps the bcd-relative gfi's to the real world. ******************************************************************** 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? imports an interface or a module outside of the bcd module hasn't been loaded yet. Put it on the list. name _ Atom.GetPName[atom]; 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 this is an expensive procedure! get the link 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. ******************************************************************** ******************************************************************** testing and initialization ******************************************************************** Ê ¹˜Jšœ™Jšœ)™)Jšœ:™:Jšœ8™8J˜šÏk ˜ Jšœœ˜Jšœ œ˜$šœœ˜J˜O—šœœ˜J˜J—J˜Jšœ œ ˜Jšœœ˜Jšœœ˜)Jšœœ˜&Jšœœ ˜!Jšœœ˜šœœ˜J˜?J˜2J˜—šœ œ˜J˜&J˜*—Jšœœ œ˜&Jšœœ˜šœœ˜ J˜*J˜1—Jšœœ˜J˜—Jšœ˜Jšœ‰˜Jšœ.˜5Jšœ œ˜Jšœ#˜'J˜Jšœœ˜Jšœœœœ˜-Jšœ2™2J˜JšœD™DJšœN™NJšœT™TJšœ™JšœD™DJ˜šÏnœœœ,˜=Jšœ œœ˜#Jš˜J˜š ž œœœœœ˜NJš˜J˜"Jšœ1œ˜DJš œ œœœÏc˜8Jšœ/™/J˜Jšœ#™#šœœœ"˜1Jšœœ˜ Jšœ œ˜Jšœœ˜ J˜J˜J˜J˜Jšœ œœ ˜J˜Jšœ™šœœœ˜&J˜-J˜3Jšœœ˜—Jšœ)™)šœœ˜'J˜šœœ˜J˜1šœœ˜1JšœŸ˜9Jšœ,œ˜7—J˜Jšœœ˜—J˜Jšœ˜—Jšœ3™3Jšœœœœ˜J˜,Jšœ˜J˜—J™JšœD™DJšœ*™*JšœD™DJ˜J˜Jšœœ˜Jš œœœœœœ˜J˜EJ˜/J˜$——J˜J˜—š žœœœ œœ˜OJšœœ˜J˜—šžœœ'˜@Jšœœ œ˜9J˜—šžœœœ(˜CJšœœ œ ˜:J˜—JšœD™DJšœ™JšœD™DJ˜Jšœœ˜ Jšœœœ˜"J˜š žœœœœœœ˜HJ˜—š ž œœœœœ˜:Jš˜Jšœ˜J˜ J˜ J˜&J˜ Jš œœœœœ˜0šœœ ˜#Jšœœœœ˜(J˜J˜J˜J˜J˜Jšœ˜—J˜Jš œœœœœ˜2Jšœ ˜Jšœ˜J˜—šžœœœœ˜#Jš˜J˜J˜J˜Jšœ=œ˜CJ˜Jšœ˜—J˜JšœœŸ˜8J˜Jšœ˜ J˜˜J˜——…—$¸7õ