-- file Pass4B.Mesa -- last modified by Satterthwaite, October 30, 1979 2:59 PM DIRECTORY AltoDefs: FROM "altodefs" USING [PageSize], BcdDefs: FROM "bcddefs" USING [ BCD, CodeDesc, ControlLink, EPIndex, EVIndex, EVRecord, EXPRecord, FrameFrag, FTIndex, FTRecord, GFTIndex, IMPIndex, IMPRecord, MTRecord, Namee, NameRecord, NameString, NTRecord, SGIndex, SGRecord, VersionID, CTNull, EVNull, FTSelf, NullLink, NullName], ComData: FROM "comdata" USING [ codeSeg, compilerVersion, definitionsOnly, fixupLoc, mainBody, mainCtx, moduleCtx, mtRoot, nBodies, nSigCodes, objectVersion, ownSymbols, sourceFile, sourceVersion, switches, symSeg, textIndex], CompilerUtil: FROM "compilerutil" USING [ AppendBCDString, AppendBCDWord, AppendBCDWords, EndBCD, ReadBCDIndex, ReadBCDOffset, StartBCD, UpdateBCDWords], Copier: FROM "copier" USING [FreeSymbolTable, GetSymbolTable], Log: FROM "log" USING [ErrorN, ErrorSei, WarningSei], P4: FROM "p4" USING [OperandType], Pass4: FROM "pass4" USING [resident], StringDefs: FROM "stringdefs" USING [ SubString, SubStringDescriptor, AppendString, AppendSubString, EqualSubStrings, EquivalentSubStrings], Symbols: FROM "symbols" USING [bodyType, ctxType, mdType, seType, HTIndex, ISEIndex, CSEIndex, RecordSEIndex, CTXIndex, IncludedCTXIndex, BitAddress, Linkage, MDRecord, MDIndex, HTNull, SENull, ISENull, CTXNull, OwnMdi], SymbolOps: FROM "symbolops" USING [ FindString, NextSe, SearchContext, SubStringForHash, UnderType, XferMode], SystemDefs: FROM "systemdefs" USING [ AllocateHeapNode, AllocateHeapString, FreeHeapNode, FreeHeapString], Table: FROM "table" USING [Base, Notifier], Tree: FROM "tree" USING [treeType, Index, Link, Map, Scan], TreeOps: FROM "treeops" USING [GetNode, ListLength, ScanList, UpdateList], Types: FROM "types" USING [SymbolTableBase, Assignable, Equivalent]; Pass4B: PROGRAM IMPORTS CompilerUtil, Copier, Log, P4, StringDefs, SymbolOps, SystemDefs, TreeOps, Types, dataPtr: ComData, passPtr: Pass4 EXPORTS P4 = BEGIN OPEN SymbolOps, Symbols; tb: Table.Base; -- tree base address (local copy) seb: Table.Base; -- se table base address (local copy) ctxb: Table.Base; -- context table base address (local copy) mdb: Table.Base; -- body table base address (local copy) bb: Table.Base; -- body table base address (local copy) BCDNotify: PUBLIC Table.Notifier = BEGIN -- called by allocator whenever table area is repacked tb ← base[Tree.treeType]; seb ← base[seType]; ctxb ← base[ctxType]; mdb ← base[mdType]; bb ← base[bodyType]; END; -- shared variables bcdHeader: POINTER TO BcdDefs.BCD; bcdOffset, mtOffset: CARDINAL; nString: BcdDefs.NameString; firstPorted: MDIndex = FIRST[MDIndex] + SIZE[MDRecord]; lastPorted: MDIndex; -- im/exported files in [firstPorted..lastPorted) -- service routines GFTIndex: TYPE = BcdDefs.GFTIndex; EPIndex: TYPE = BcdDefs.EPIndex; EPLimit: CARDINAL = LAST[EPIndex]+1; ControlLink: TYPE = BcdDefs.ControlLink; OwnGfi: GFTIndex = 1; GFSlots: PROCEDURE [epMax: EPIndex] RETURNS [nGfi: [1..4]] = BEGIN nGfi ← epMax/EPLimit + 1; RETURN END; MakeEPLink: PUBLIC PROCEDURE [ep: CARDINAL, gfi: GFTIndex] RETURNS [ControlLink] = BEGIN RETURN [ControlLink[procedure[ tag: procedure, ep: ep MOD EPLimit, gfi: gfi + ep/EPLimit]]] END; MakeFrameLink: PROCEDURE [ep: CARDINAL, gfi: GFTIndex] RETURNS [ControlLink] = BEGIN RETURN [ControlLink[procedure[ tag: frame, ep: ep MOD EPLimit, gfi: gfi + ep/EPLimit]]] END; PortedFile: PROCEDURE [ctx: CTXIndex] RETURNS [fti: BcdDefs.FTIndex] = BEGIN mdi: MDIndex; n: CARDINAL; mdi ← WITH c: ctxb[ctx] SELECT FROM included => c.module, imported => ctxb[c.includeLink].module, ENDCASE => OwnMdi; IF mdi = OwnMdi THEN fti ← BcdDefs.FTSelf ELSE BEGIN IF mdi IN [firstPorted .. lastPorted) THEN n ← LOOPHOLE[mdi-firstPorted, CARDINAL]/SIZE[MDRecord] ELSE BEGIN n ← LOOPHOLE[lastPorted-firstPorted, CARDINAL]/SIZE[MDRecord]; SwapMdi[mdi, lastPorted]; lastPorted ← lastPorted + SIZE[MDRecord]; END; fti ← LOOPHOLE[n*SIZE[BcdDefs.FTRecord]]; END; RETURN END; SwapMdi: PROCEDURE [mdi1, mdi2: MDIndex] = BEGIN ctx: IncludedCTXIndex; t: MDRecord; IF mdi1 # mdi2 THEN BEGIN FOR ctx ← mdb[mdi1].ctx, ctxb[ctx].chain UNTIL ctx = CTXNull DO ctxb[ctx].module ← mdi2 ENDLOOP; FOR ctx ← mdb[mdi2].ctx, ctxb[ctx].chain UNTIL ctx = CTXNull DO ctxb[ctx].module ← mdi1 ENDLOOP; t ← mdb[mdi1]; mdb[mdi1] ← mdb[mdi2]; mdb[mdi2] ← t; END; END; SubString: TYPE = StringDefs.SubString; SubStringDescriptor: TYPE = StringDefs.SubStringDescriptor; EnterId: PROCEDURE [id: SubString, ignoreCase: BOOLEAN] RETURNS [BcdDefs.NameRecord] = BEGIN i: CARDINAL; desc: SubStringDescriptor; s: SubString = @desc; t: BcdDefs.NameString; i ← 0; s.base ← @nString.string; UNTIL i = nString.string.length DO s.offset ← i ← i+1; s.length ← nString.size[i]; IF (IF ignoreCase THEN StringDefs.EquivalentSubStrings ELSE StringDefs.EqualSubStrings)[id, s] THEN EXIT; i ← i + s.length; REPEAT FINISHED => BEGIN IF nString.string.length + (id.length+1) > nString.string.maxlength THEN BEGIN -- rewrite if nString is in table area t ← LOOPHOLE[SystemDefs.AllocateHeapString[ nString.string.maxlength + MAX[(id.length+1), 32]]]; StringDefs.AppendString[@t.string, @nString.string]; SystemDefs.FreeHeapString[@nString.string]; nString ← t; END; i ← nString.string.length ← nString.string.length + 1; nString.size[i] ← id.length; StringDefs.AppendSubString[@nString.string, id]; END; ENDLOOP; RETURN [[i]] END; EnterSymbolId: PROCEDURE [sei: ISEIndex] RETURNS [BcdDefs.NameRecord] = BEGIN s: SubStringDescriptor; SubStringForHash[@s, seb[sei].hash]; RETURN [EnterId[@s, FALSE]] END; EnterFileId: PROCEDURE [mdi: MDIndex] RETURNS [BcdDefs.NameRecord] = BEGIN s, dExt: SubStringDescriptor; bcd: STRING = ".bcd."; dBcd: SubStringDescriptor ← [base:bcd, offset:0, length:bcd.length]; SubStringForHash[@s, mdb[mdi].fileId]; dExt ← [base: s.base, offset: s.offset+s.length-bcd.length, length: bcd.length]; IF StringDefs.EquivalentSubStrings[@dExt, @dBcd] THEN s.length ← s.length - bcd.length; RETURN [EnterId[@s, TRUE]] END; TreeSymbol: PROCEDURE [t: Tree.Link] RETURNS [ISEIndex] = BEGIN WITH t SELECT FROM symbol => RETURN [index]; ENDCASE => ERROR; END; -- relocating imported control links RelocateImports: PROCEDURE [ctx: CTXIndex, gfi: GFTIndex] RETURNS [epMax: EPIndex] = BEGIN sei: ISEIndex; epN: CARDINAL; epMax ← 0; IF ctx = CTXNull THEN RETURN; FOR sei ← ctxb[ctx].seList, NextSe[sei] UNTIL sei = SENull DO IF ~seb[sei].constant THEN BEGIN epN ← seb[sei].idValue; epMax ← MAX[epN, epMax]; seb[sei].idValue ← SELECT XferMode[seb[sei].idType] FROM procedure, signal, error => MakeEPLink[epN, gfi], ENDCASE => MakeFrameLink[epN, gfi]; END; ENDLOOP; RETURN END; AssignImports: PUBLIC Tree.Scan = BEGIN gfi: GFTIndex; saveIndex: CARDINAL = dataPtr.textIndex; ImportItem: Tree.Scan = BEGIN node: Tree.Index = TreeOps.GetNode[t]; sei: ISEIndex = TreeSymbol[tb[node].son[1]]; type: CSEIndex = UnderType[seb[sei].idType]; epMax: EPIndex; dataPtr.textIndex ← tb[node].info; WITH seb[type] SELECT FROM definition => BEGIN IF ctxb[defCtx].seList = SENull THEN WITH c: ctxb[defCtx] SELECT FROM imported => IF tb[node].attr1 OR ~mdb[ctxb[c.includeLink].module].exported THEN Log.WarningSei[unusedImport, sei]; ENDCASE; epMax ← RelocateImports[defCtx, gfi]; seb[sei].idValue ← gfi; gfi ← gfi + (seb[sei].idInfo ← nGfi); -- consider adding GFSlots[epMax] instead -- END; pointer => BEGIN seb[sei].idValue ← MakeFrameLink[ep:0, gfi:gfi]; gfi ← gfi + 1; END; ENDCASE; seb[sei].mark4 ← TRUE; END; dataPtr.mtRoot.gfi ← OwnGfi; dataPtr.mtRoot.ngfi ← GFSlots[MAX[dataPtr.nBodies, dataPtr.nSigCodes]-1]; gfi ← bcdHeader.firstdummy ← OwnGfi + dataPtr.mtRoot.ngfi; IF ~dataPtr.definitionsOnly THEN TreeOps.ScanList[t, ImportItem]; bcdHeader.nDummies ← gfi - bcdHeader.firstdummy; dataPtr.textIndex ← saveIndex; END; -- writing import records ProcessImports: PUBLIC Tree.Scan = BEGIN -- N.B. nextGfi must be regenerated to match AssignImports nImports: CARDINAL; impi: BcdDefs.IMPIndex; nextGfi: GFTIndex; anyNamed: BOOLEAN; ImportItem: Tree.Scan = BEGIN node: Tree.Index = TreeOps.GetNode[t]; sei1: ISEIndex = TreeSymbol[tb[node].son[1]]; sei2: ISEIndex = TreeSymbol[tb[node].son[2]]; type: CSEIndex; rType: RecordSEIndex; entry: BcdDefs.IMPRecord; entry ← [ name: EnterSymbolId[sei2], port: interface, namedinstance: seb[sei1].hash # seb[sei2].hash, file: , gfi: , ngfi: ]; type ← UnderType[seb[sei1].idType]; WITH seb[type] SELECT FROM definition => BEGIN entry.file ← PortedFile[defCtx]; entry.gfi ← seb[sei1].idValue; entry.ngfi ← seb[sei1].idInfo; nextGfi ← seb[sei1].idValue + seb[sei1].idInfo; END; pointer => BEGIN entry.port ← module; rType ← LOOPHOLE[UnderType[refType]]; entry.file ← PortedFile[seb[rType].fieldCtx]; entry.gfi ← nextGfi; entry.ngfi ← 1; nextGfi ← nextGfi + 1; END; ENDCASE; nImports ← nImports + 1; IF entry.namedinstance THEN anyNamed ← TRUE; CompilerUtil.AppendBCDWords[@entry, SIZE[BcdDefs.IMPRecord]]; END; NameItem: Tree.Scan = BEGIN node: Tree.Index = TreeOps.GetNode[t]; sei1: ISEIndex = TreeSymbol[tb[node].son[1]]; sei2: ISEIndex = TreeSymbol[tb[node].son[2]]; entry: BcdDefs.NTRecord; IF seb[sei1].hash # seb[sei2].hash THEN BEGIN entry ← [ name: EnterSymbolId[sei1], item: BcdDefs.Namee[import[impi]]]; CompilerUtil.AppendBCDWords[@entry, SIZE[BcdDefs.NTRecord]]; END; impi ← impi + SIZE[BcdDefs.IMPRecord]; END; offset: CARDINAL; bcdHeader.impOffset ← offset ← CompilerUtil.ReadBCDOffset[]; nImports ← 0; impi ← FIRST[BcdDefs.IMPIndex]; nextGfi ← bcdHeader.firstdummy; anyNamed ← FALSE; IF ~dataPtr.definitionsOnly THEN TreeOps.ScanList[t, ImportItem]; bcdHeader.nImports ← nImports; bcdHeader.impLimit ← LOOPHOLE[CompilerUtil.ReadBCDOffset[]-offset]; bcdHeader.ntOffset ← offset ← CompilerUtil.ReadBCDOffset[]; IF anyNamed THEN TreeOps.ScanList[t, NameItem]; bcdHeader.ntLimit ← LOOPHOLE[CompilerUtil.ReadBCDOffset[]-offset]; END; -- writing export records maxEVLength: CARDINAL; evList: POINTER TO BcdDefs.EVRecord; EnterEVOffset: PROCEDURE [offset: CARDINAL] RETURNS [index: CARDINAL] = BEGIN IF offset = 0 THEN index ← 0 ELSE FOR index IN [1 .. evList.length] DO IF offset = evList.offsets[index] THEN EXIT; REPEAT FINISHED => BEGIN index ← evList.length ← evList.length + 1; IF index <= maxEVLength THEN evList.offsets[index] ← offset; END; ENDLOOP; RETURN END; ExportId: Tree.Map = BEGIN type: CSEIndex = P4.OperandType[t]; ctx: IncludedCTXIndex; iBase: Types.SymbolTableBase; id, sei, iSei: ISEIndex; mode: Linkage; link: ControlLink; public, used: BOOLEAN; id ← TreeSymbol[t]; WITH v: seb[type] SELECT FROM definition => BEGIN ctx ← LOOPHOLE[v.defCtx]; iBase ← Copier.GetSymbolTable[ctxb[ctx].module]; IF iBase # NIL THEN BEGIN BEGIN header: BcdDefs.EXPRecord ← [ name: EnterSymbolId[id], size: 0, port: interface, namedinstance: FALSE, file: PortedFile[v.defCtx], links: ]; FOR iSei ← iBase.FirstCtxSe[ctxb[ctx].map], iBase.NextSe[iSei] UNTIL iSei = SENull DO IF iBase.LinkMode[iSei] # manifest THEN header.size ← header.size + 1; ENDLOOP; CompilerUtil.AppendBCDWords[@header, SIZE[BcdDefs.EXPRecord]]; END; used ← FALSE; FOR iSei ← iBase.FirstCtxSe[ctxb[ctx].map], iBase.NextSe[iSei] UNTIL iSei = SENull DO mode ← iBase.LinkMode[iSei]; link ← BcdDefs.NullLink; BEGIN ss: SubStringDescriptor; hti: HTIndex; iBase.SubStringForHash[@ss, iBase.seb[iSei].hash]; hti ← FindString[@ss]; IF hti = HTNull THEN sei ← ISENull ELSE BEGIN sei ← SearchContext[hti, dataPtr.mainCtx]; IF sei = SENull THEN sei ← SearchContext[hti, dataPtr.moduleCtx]; END; END; IF sei # SENull THEN BEGIN public ← seb[sei].public; SELECT mode FROM val => BEGIN IF ~Types.Assignable[ [iBase, iBase.UnderType[iBase.seb[iSei].idType]], [dataPtr.ownSymbols, UnderType[seb[sei].idType]]] THEN BEGIN IF public THEN Log.ErrorSei[exportClash,sei] END ELSE IF ~public AND seb[sei].idCtx = dataPtr.mainCtx THEN Log.WarningSei[privateExport, sei]; IF public THEN BEGIN IF ~seb[sei].constant OR seb[sei].extended THEN Log.ErrorSei[varExport, sei]; link ← IF XferMode[seb[sei].idType] = program THEN MakeFrameLink[ep:EnterEVOffset[0], gfi:OwnGfi] ELSE seb[sei].idValue; END; END; ref => BEGIN IF ~Types.Equivalent[ [iBase, iBase.UnderType[iBase.seb[iSei].idType]], [dataPtr.ownSymbols, UnderType[seb[sei].idType]]] THEN BEGIN IF public THEN Log.ErrorSei[exportClash,sei] END ELSE IF ~public AND seb[sei].idCtx = dataPtr.mainCtx THEN Log.WarningSei[privateExport, sei]; IF public THEN BEGIN SELECT TRUE FROM seb[sei].constant => Log.ErrorSei[varExport, sei]; seb[sei].immutable AND ~iBase.seb[iSei].immutable => Log.ErrorSei[exportClash, sei]; ENDCASE; link ← MakeFrameLink[ ep: EnterEVOffset[ LOOPHOLE[seb[sei].idValue, BitAddress].wd], gfi: OwnGfi]; END; END; manifest => IF public THEN Log.WarningSei[voidExport, sei]; ENDCASE; END; IF link # BcdDefs.NullLink THEN used ← TRUE; IF mode # manifest THEN CompilerUtil.AppendBCDWord[link]; ENDLOOP; Copier.FreeSymbolTable[iBase]; IF ~used THEN Log.WarningSei[unusedExport, id]; END; END; ENDCASE; RETURN [t] END; ProcessExports: PUBLIC Tree.Map = BEGIN offset: CARDINAL; bcdHeader.nExports ← TreeOps.ListLength[t]; bcdHeader.expOffset ← offset ← CompilerUtil.ReadBCDOffset[]; maxEVLength ← dataPtr.mtRoot.ngfi*EPLimit - 1; evList ← SystemDefs.AllocateHeapNode[SIZE[BcdDefs.EVRecord]+maxEVLength]; evList↑ ← [length:0, offsets:]; v ← TreeOps.UpdateList[t, ExportId]; bcdHeader.expLimit ← LOOPHOLE[CompilerUtil.ReadBCDOffset[]-offset]; bcdHeader.evOffset ← offset ← CompilerUtil.ReadBCDOffset[]; IF evList.length > maxEVLength THEN Log.ErrorN[exportedVars, evList.length-maxEVLength]; IF evList.length = 0 THEN dataPtr.mtRoot.variables ← BcdDefs.EVNull ELSE BEGIN dataPtr.mtRoot.variables ← FIRST[BcdDefs.EVIndex]; CompilerUtil.AppendBCDWords[evList, SIZE[BcdDefs.EVRecord] + MIN[evList.length, maxEVLength]]; END; bcdHeader.evLimit ← LOOPHOLE[CompilerUtil.ReadBCDOffset[]-offset]; SystemDefs.FreeHeapNode[evList]; RETURN END; -- initialization/finalization ProcessFiles: PROCEDURE = BEGIN ftEntry: BcdDefs.FTRecord; mdi: MDIndex; offset: CARDINAL = CompilerUtil.ReadBCDOffset[]; bcdHeader.ftOffset ← offset; FOR mdi ← firstPorted, mdi+SIZE[MDRecord] UNTIL mdi = lastPorted DO ftEntry ← [name: EnterFileId[mdi], version: mdb[mdi].stamp]; CompilerUtil.AppendBCDWords[@ftEntry, SIZE[BcdDefs.FTRecord]]; ENDLOOP; bcdHeader.ftLimit ← LOOPHOLE[CompilerUtil.ReadBCDOffset[] - offset]; END; MTRootSize: CARDINAL = SIZE[BcdDefs.MTRecord]-SIZE[BcdDefs.FrameFrag]; InitBCD: PUBLIC PROCEDURE = BEGIN OPEN BcdDefs; lastPorted ← firstPorted; nString ← LOOPHOLE[SystemDefs.AllocateHeapString[64]]; -- allocate the null name nString.string.length ← BcdDefs.NullName; nString.size[BcdDefs.NullName] ← 0; CompilerUtil.StartBCD[]; bcdHeader ← SystemDefs.AllocateHeapNode[SIZE[BCD]]; bcdHeader.versionident ← VersionID; bcdHeader.version ← dataPtr.objectVersion; bcdHeader.sourceVersion ← dataPtr.sourceVersion; bcdHeader.creator ← dataPtr.compilerVersion; bcdHeader.nConfigs ← 0; bcdHeader.nModules ← 1; bcdHeader.nImports ← bcdHeader.nExports ← 0; bcdHeader.definitions ← dataPtr.definitionsOnly; bcdHeader.ctOffset ← 0; bcdHeader.ctLimit ← LOOPHOLE[0]; bcdHeader.spOffset ← 0; bcdHeader.spLimit ← LOOPHOLE[0]; nString.string.length ← nString.string.length + 1; bcdHeader.source ← NameRecord[nString.string.length]; nString.size[bcdHeader.source] ← dataPtr.sourceFile.length; StringDefs.AppendString[@nString.string, dataPtr.sourceFile]; bcdOffset ← CompilerUtil.ReadBCDOffset[]; CompilerUtil.AppendBCDWords[bcdHeader, SIZE[BCD]]; dataPtr.fixupLoc ← CompilerUtil.ReadBCDIndex[]; bcdHeader.sgOffset ← CompilerUtil.ReadBCDOffset[]; CompilerUtil.AppendBCDWords[@dataPtr.codeSeg, SIZE[SGRecord]]; CompilerUtil.AppendBCDWords[@dataPtr.symSeg, SIZE[SGRecord]]; bcdHeader.mtOffset ← mtOffset ← CompilerUtil.ReadBCDOffset[]; bcdHeader.sgLimit ← LOOPHOLE[mtOffset - bcdHeader.sgOffset]; CompilerUtil.AppendBCDWords[@dataPtr.mtRoot, MTRootSize]; END; FinishBCD: PUBLIC PROCEDURE = BEGIN OPEN BcdDefs; PageSize: CARDINAL = AltoDefs.PageSize; bcdSize: CARDINAL; -- fill MTRecord dataPtr.mtRoot.name ← EnterSymbolId[bb[dataPtr.mainBody].id]; dataPtr.mtRoot.namedinstance ← FALSE; dataPtr.mtRoot.initial ← FALSE; dataPtr.mtRoot.file ← dataPtr.codeSeg.file ← dataPtr.symSeg.file ← PortedFile[dataPtr.mainCtx]; dataPtr.mtRoot.links ← frame; dataPtr.mtRoot.config ← CTNull; dataPtr.mtRoot.code ← CodeDesc[ sgi: FIRST[SGIndex], packed: FALSE, linkspace: FALSE, offset: 0, length: ]; dataPtr.mtRoot.sseg ← FIRST[SGIndex] + SIZE[SGRecord]; dataPtr.mtRoot.altoCode ← dataPtr.switches['a]; dataPtr.mtRoot.residentFrame ← passPtr.resident; dataPtr.mtRoot.attr3 ← FALSE; dataPtr.mtRoot.sseg ← FIRST[SGIndex] + SIZE[SGRecord]; bcdHeader.mtLimit ← LOOPHOLE[bcdHeader.impOffset-bcdHeader.mtOffset]; ProcessFiles[]; bcdHeader.ssOffset ← CompilerUtil.ReadBCDOffset[]; CompilerUtil.AppendBCDString[@nString.string]; bcdSize ← CompilerUtil.ReadBCDOffset[]; bcdHeader.ssLimit ← LOOPHOLE[bcdSize-bcdHeader.ssOffset]; bcdHeader.nPages ← (bcdSize + (PageSize-1))/PageSize; CompilerUtil.UpdateBCDWords[bcdOffset, bcdHeader, SIZE[BCD]]; CompilerUtil.EndBCD[]; SystemDefs.FreeHeapString[@nString.string]; SystemDefs.FreeHeapNode[bcdHeader]; END; END.