-- SMFakeBcdImpl.mesa -- last edit by Schmidt, May 24, 1983 3:13 pm -- last edit by Satterthwaite, August 12, 1983 1:09 pm -- procedures to build the fake config in the compile tool DIRECTORY BcdDefs: TYPE USING [ Base, BCD, CTIndex, CTNull, CTRecord, EXPIndex, FTIndex, FTNull, FTRecord, FTSelf, GFTIndex, Link, MTIndex, MTRecord, NameRecord, NullVersion, SGIndex, SGRecord, VersionID], BcdOps: TYPE USING [BcdBase, MTHandle, NameString, ProcessModules], Directory: TYPE USING [ignore, Lookup, Error], Environment: TYPE USING [wordsPerPage], File: TYPE USING [Capability], IO: TYPE USING [card, PutF, PutFR, rope, STREAM], CS: TYPE USING [NewFile, readWrite], PilotLoadStateFormat: TYPE USING [ConfigIndex], PilotLoadStateOps: TYPE USING [ ConfigIndex, EnterModule, GetMap, Map, ReleaseLoadState, ReleaseMap, UpdateLoadState], PrincOps: TYPE USING [GFTIndex], Rope: TYPE USING [Text], RopeInline: TYPE USING [InlineFlatten], SMFakeBcd: TYPE USING [], SMLoad: TYPE USING [Zero], SMTree: TYPE Tree USING [ApplOp, Handle, Link], SMTreeOps: TYPE USING [OpName, Scan, ScanSons], SMVal: TYPE USING [LoadMod, GetExtFromParse], Space: TYPE USING [ Create, Delete, Handle, LongPointer, Map, nullHandle, virtualMemory]; SMFakeBcdImpl: PROGRAM IMPORTS BcdOps, CS, Directory, SMLoad, SMTreeOps, SMVal, IO, PilotLoadStateOps, RopeInline, Space EXPORTS SMFakeBcd ~ { OPEN Tree~~SMTree, TreeOps~~SMTreeOps; -- no MDS usage! MTPAGE: CARDINAL ~ (BcdDefs.BCD.SIZE/Environment.wordsPerPage) + 1; nmtp: CARDINAL ~ 20; FTPAGE: CARDINAL ~ MTPAGE + nmtp; nftp: CARDINAL ~ 6; SGPAGE: CARDINAL ~ FTPAGE + nftp; nsgp: CARDINAL ~ 6; CTPAGE: CARDINAL ~ SGPAGE + nsgp; nctp: CARDINAL ~ 1; SSPAGE: CARDINAL ~ CTPAGE + nctp; nssp: CARDINAL ~ 16; EXPAGE: CARDINAL ~ SSPAGE + nssp; nexp: CARDINAL ~ 3; BCDPAGES: CARDINAL ~ EXPAGE + nexp; -- also updates the load state with the modules BuildFakeBcd: PUBLIC SAFE PROC[ configIndex: PilotLoadStateFormat.ConfigIndex, root: Tree.Link, oldFakeBcdFileName: Rope.Text, oldFakeBcdSpace: Space.Handle, out: IO.STREAM] RETURNS [fakeBcdFileName: Rope.Text, fakeBcdSpace: Space.Handle] ~ TRUSTED { bcdSpace: Space.Handle ← Space.nullHandle; { ENABLE UNWIND => { IF bcdSpace ~= Space.nullHandle AND oldFakeBcdSpace = Space.nullHandle THEN Space.Delete[bcdSpace] }; Cbcdbase: BcdOps.BcdBase; Cctb, Cmtb, Csgb, Cftb, Cetb: BcdDefs.Base; Cmti: BcdDefs.MTIndex ← BcdDefs.MTIndex.FIRST; Cfti: BcdDefs.FTIndex ← BcdDefs.FTIndex.FIRST; Csgi: BcdDefs.SGIndex ← BcdDefs.SGIndex.FIRST; Ceti: BcdDefs.EXPIndex ← BcdDefs.EXPIndex.FIRST; Cnamei: CARDINAL; Cnamestring: BcdOps.NameString; Cngfi: CARDINAL ← 1; ProcAnalyze: PROC[loadMod: SMVal.LoadMod] ~ { sgb, ftb: BcdDefs.Base; bcdbase: BcdOps.BcdBase; namestring: BcdOps.NameString; ForEachModule: PROC[mth: BcdOps.MTHandle, mti: BcdDefs.MTIndex] RETURNS[stop: BOOL←FALSE] ~ { rgfi: PrincOps.GFTIndex; Check[Cmti + MTRecordLength[mth], Cbcdbase.mtLimit]; Cmtb[Cmti] ← mth↑; Cmtb[Cmti].name ← NewName[namestring, mth.name]; Cmtb[Cmti].gfi ← Cngfi; Cmtb[Cmti].extension ← direct[length~0, frag~]; IF mth.gfi >= loadMod.loadInfo.gfiMap.size THEN ERROR; -- this has previously been done in -- CedarLoaderImpl.CreateGlobalFrames -- we do it here to set the map for the fake config rgfi ← loadMod.loadInfo.gfiMap[mth.gfi].index; FOR i: CARDINAL IN [0 .. mth.ngfi) DO PilotLoadStateOps.EnterModule[ rgfi+i, [resolved~TRUE, config~configIndex, gfi~Cngfi+i]]; ENDLOOP; Cngfi ← Cngfi + mth.ngfi; Check[Cfti + BcdDefs.FTRecord.SIZE, Cbcdbase.ftLimit]; IF mth.file = BcdDefs.FTSelf THEN { -- get info from header Cftb[Cfti] ← [NewName[namestring, bcdbase.source], bcdbase.version]; Cmtb[Cmti].file ← Cfti; Cfti ← Cfti + BcdDefs.FTRecord.SIZE} ELSE IF mth.file = BcdDefs.FTNull THEN { Cmtb[Cmti].file ← BcdDefs.FTNull} ELSE { Cftb[Cfti] ← ftb[mth.file]; Cftb[Cfti].name ← NewName[namestring, ftb[mth.file].name]; Cmtb[Cmti].file ← Cfti; Cfti ← Cfti + BcdDefs.FTRecord.SIZE}; Check[Csgi + BcdDefs.SGRecord.SIZE, Cbcdbase.sgLimit]; Csgb[Csgi] ← sgb[mth.sseg]; Cmtb[Cmti].sseg ← Csgi; Check[Cfti + BcdDefs.FTRecord.SIZE, Cbcdbase.ftLimit]; IF Csgb[Csgi].file = BcdDefs.FTSelf THEN { -- if self then the symbols are in the config's file Cftb[Cfti] ← [NewString[loadMod.proj.localName], bcdbase.version]; Csgb[Csgi].file ← Cfti; Cfti ← Cfti + BcdDefs.FTRecord.SIZE} ELSE IF Csgb[Csgi].file = BcdDefs.FTNull THEN { Csgb[Csgi].file ← BcdDefs.FTNull} ELSE { Cftb[Cfti] ← ftb[Csgb[Csgi].file]; Cftb[Cfti].name ← NewName[namestring, ftb[Csgb[Csgi].file].name]; Csgb[Csgi].file ← Cfti; Cfti ← Cfti + BcdDefs.FTRecord.SIZE}; Csgi ← Csgi + BcdDefs.SGRecord.SIZE; Cmti ← Cmti + BcdDefs.MTRecord.direct.SIZE; Cbcdbase.nModules ← Cbcdbase.nModules + 1}; IF loadMod.loadInfo = NIL THEN RETURN; bcdbase ← loadMod.loadInfo.bcdBase; sgb ← LOOPHOLE[bcdbase + bcdbase.sgOffset, BcdDefs.Base]; ftb ← LOOPHOLE[bcdbase + bcdbase.ftOffset, BcdDefs.Base]; namestring ← LOOPHOLE[bcdbase + bcdbase.ssOffset]; [] ← BcdOps.ProcessModules[bcdbase, ForEachModule]}; NewName: PROC[namestring: BcdOps.NameString, oldname: BcdDefs.NameRecord] RETURNS[newname: BcdDefs.NameRecord] ~ { newname ← LOOPHOLE[Cnamei]; Check[(Cnamei + namestring.size[oldname] + 1)/2 + 1, Cbcdbase.ssLimit]; Cnamestring.size[newname] ← namestring.size[oldname]; FOR i: CARDINAL IN [0 .. Cnamestring.size[newname]) DO Cnamestring.string.text[newname + i] ← namestring.string.text[oldname + i]; ENDLOOP; Cnamei ← Cnamei + Cnamestring.size[newname] + 1}; NewString: PROC[oldrope: Rope.Text] RETURNS[newname: BcdDefs.NameRecord] ~ { oldstring: LONG STRING ← LOOPHOLE[oldrope]; newname ← LOOPHOLE[Cnamei]; Check[(Cnamei + oldstring.length + 1)/2, Cbcdbase.ssLimit]; Cnamestring.size[newname] ← oldstring.length; FOR i: CARDINAL IN [0 .. Cnamestring.size[newname]) DO Cnamestring.string.text[newname + i] ← oldstring[i]; ENDLOOP; Cnamei ← Cnamei + Cnamestring.size[newname] + 1}; -- traverses the value tree ForEachApply: TreeOps.Scan ~ TRUSTED { WITH t SELECT FROM node: Tree.Handle => { TreeOps.ScanSons[node, ForEachApply]; -- postorder IF TreeOps.OpName[node] IN Tree.ApplOp THEN WITH SMVal.GetExtFromParse[node] SELECT FROM loadMod: SMVal.LoadMod => ProcAnalyze[loadMod]; ENDCASE; }; ENDCASE => NULL; }; { map: PilotLoadStateOps.Map; IF oldFakeBcdSpace ~= Space.nullHandle THEN { bcdSpace ← oldFakeBcdSpace; -- assumed mapped fakeBcdFileName ← oldFakeBcdFileName} ELSE { cap: File.Capability; bcdSpace ← Space.Create[size~BCDPAGES, parent~Space.virtualMemory]; fakeBcdFileName ← GenUniqueBcdName["FakeConfig"]; cap ← CS.NewFile[fakeBcdFileName, CS.readWrite, BCDPAGES]; bcdSpace.Map[window~[cap, 1]]}; Cbcdbase ← bcdSpace.LongPointer; [] ← SMLoad.Zero[Cbcdbase, BCDPAGES * Environment.wordsPerPage]; Cbcdbase.versionIdent ← BcdDefs.VersionID; Cbcdbase.nPages ← BCDPAGES; Cbcdbase.version ← BcdDefs.NullVersion; Cbcdbase.nConfigs ← 1; Cbcdbase.nModules ← 0; Cbcdbase.extended ← TRUE; -- to keep the RT happy Cbcdbase.nImports ← Cbcdbase.nExports ← 0; -- all the Limit vars are set to 0 Cbcdbase.impOffset ← Cbcdbase.evOffset ← 0; Cbcdbase.spOffset ← Cbcdbase.ntOffset ← Cbcdbase.typOffset ← 0; Cbcdbase.tmOffset ← Cbcdbase.fpOffset ← 0; Cbcdbase.ctOffset ← CTPAGE * Environment.wordsPerPage; Cbcdbase.mtOffset ← MTPAGE * Environment.wordsPerPage; Cbcdbase.sgOffset ← SGPAGE * Environment.wordsPerPage; Cbcdbase.ftOffset ← FTPAGE * Environment.wordsPerPage; Cbcdbase.expOffset ← EXPAGE * Environment.wordsPerPage; Cbcdbase.ssOffset ← SSPAGE * Environment.wordsPerPage; Cnamei ← 0; Cctb ← LOOPHOLE[Cbcdbase + Cbcdbase.ctOffset, BcdDefs.Base]; Cmtb ← LOOPHOLE[Cbcdbase + Cbcdbase.mtOffset, BcdDefs.Base]; Csgb ← LOOPHOLE[Cbcdbase + Cbcdbase.sgOffset, BcdDefs.Base]; Cftb ← LOOPHOLE[Cbcdbase + Cbcdbase.ftOffset, BcdDefs.Base]; Cetb ← LOOPHOLE[Cbcdbase + Cbcdbase.expOffset, BcdDefs.Base]; Cnamestring ← LOOPHOLE[Cbcdbase + Cbcdbase.ssOffset, BcdDefs.Base]; Cbcdbase.ctLimit ← BcdDefs.CTIndex.FIRST + BcdDefs.CTRecord.SIZE; Cbcdbase.mtLimit ← LOOPHOLE[nmtp * Environment.wordsPerPage]; Cbcdbase.ftLimit ← LOOPHOLE[nftp * Environment.wordsPerPage]; Cbcdbase.sgLimit ← LOOPHOLE[nsgp * Environment.wordsPerPage]; Cbcdbase.expLimit ← LOOPHOLE[nexp * Environment.wordsPerPage]; Cbcdbase.ssLimit ← LOOPHOLE[nssp * Environment.wordsPerPage]; LOOPHOLE[Cnamestring+1, LONG POINTER TO CARDINAL]↑ ← (Cbcdbase.ssLimit-2)*2; -- the maxlength of namestring Cnamestring.string.length ← Cnamestring.string.maxlength; Cctb[BcdDefs.CTIndex.FIRST] ← [ name~NewString[fakeBcdFileName], namedInstance~FALSE, file~BcdDefs.FTSelf, config~BcdDefs.CTNull, nControls~0, controls~]; ForEachApply[root]; Cbcdbase.firstdummy ← Cngfi; -- # gfi's needed for the modules in the config Cbcdbase.mtLimit ← Cmti; Cbcdbase.ftLimit ← Cfti; Cbcdbase.sgLimit ← Csgi; Cbcdbase.expLimit ← Ceti; Cbcdbase.ssLimit ← (Cnamei/2)+1; fakeBcdSpace ← bcdSpace; -- now insert the new bcdbase -- newer version of BcdOps PilotLoadStateOps.UpdateLoadState[configIndex, LOOPHOLE[Cbcdbase]]; map ← PilotLoadStateOps.GetMap[configIndex]; -- CedarLinkerOps.Export[LOOPHOLE[Cbcdbase], map]; PilotLoadStateOps.ReleaseMap[map]; PilotLoadStateOps.ReleaseLoadState[]; out.PutF["Total # of gfi's needed to load: %s.\n", IO.card[Cngfi-1]]; -- this ForceOut is expensive, only need it for debugging -- bcdSpace.ForceOut; -- out.PutF["Fake bcd written out on %s\n", IO.rope[fakeBcdFileName]]; }; } }; Check: PROC[val, limit: UNSPECIFIED] ~ { IF LOOPHOLE[val, CARDINAL] >= LOOPHOLE[limit, CARDINAL] THEN ERROR}; MTRecordLength: PROC[mth: BcdOps.MTHandle] RETURNS[CARDINAL] ~ { RETURN[WITH m~~mth SELECT FROM direct => BcdDefs.MTRecord.direct.SIZE + m.length*BcdDefs.Link.SIZE, indirect => BcdDefs.MTRecord.indirect.SIZE, multiple => BcdDefs.MTRecord.multiple.SIZE, ENDCASE => ERROR]; }; GenUniqueBcdName: SAFE PROC[bcdFileName: Rope.Text] RETURNS[newName: Rope.Text] ~ TRUSTED { inx: CARDINAL ← 1; newName ← bcdFileName; DO newName ← RopeInline.InlineFlatten[ IO.PutFR["%s.%d.Bcd$", IO.rope[bcdFileName], IO.card[inx]]]; [] ← Directory.Lookup[fileName~LOOPHOLE[newName], permissions~Directory.ignore ! Directory.Error => {GOTO out}]; inx ← inx + 1; ENDLOOP; EXITS out => NULL; }; }.