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