<> <> <> <> 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 . . .