-- CodePackProcsImpl.mesa -- Last edited by Lewis on 1-Mar-82 23:55:08 -- Last edited by Satterthwaite, January 12, 1983 11:46 am DIRECTORY Alloc USING [AddNotify, DropNotify, Handle, Notifier, Words], BcdDefs USING [MTIndex, MTNull, NameRecord], CodePackProcs, Error USING [ EmptyCodePack, Error, ErrorName, EVInDiscardCodePack, EVNotFirst, ModuleAlreadyPacked, NoProcFromModuleInCP, NotProcInModule, ProcNotPlaced, ProcPlacedTwice, TableCompModuleNotIncAsUnit], HashOps USING [HTIndex, SubStringForHash], Inline USING [BITAND, BITXOR], ModuleSymbols USING [InvalidSymbols, Load, Unload, outerPackArray, FindProc], PackagerDefs USING [ globalData, GlobalData, packtreetype, packsttype, packmdtype], PackageSymbols USING [OPCatch, OPEntry, OPIndex, OPMain, OPNull], ProcessingOrder USING [Enumerate, IsEmpty], SemanticEntry USING [STIndex], SourceBcd USING [ bcdBases, CTreeIndex, EnumerateModulesInConfig, IsTableCompiled, moduleCount, ModuleNum, ModuleNumForMti], String USING [SubString, SubStringDescriptor], Symbols USING [HTIndex, HTNull], SymbolOps USING [SubStringForHash], Table USING [Base, Index, Limit], Tree: FROM "PackTree" USING [Index, Link, ProcsLink, Scan, Test, nullIndex], TreeOps: FROM "PackTreeOps" USING [ListHead, ListLength, ScanList, SearchList]; CodePackProcsImpl: PROGRAM IMPORTS Alloc, Error, HashOps, Inline, ModuleSymbols, PackagerDefs, ProcessingOrder, SymbolOps, SourceBcd, TreeOps EXPORTS CodePackProcs = BEGIN OPEN PackageSymbols, CodePackProcs; CPerror: PROC = {ERROR CodePackProcsError}; CodePackProcsError: ERROR = CODE; gd: PackagerDefs.GlobalData ← NIL; -- set by Determine table: Alloc.Handle ← NIL; tb, stb, mdb: Table.Base; UpdateBases: Alloc.Notifier = { tb ← base[PackagerDefs.packtreetype]; stb ← base[PackagerDefs.packsttype]; mdb ← base[PackagerDefs.packmdtype]}; -- ***************** Exported Types ***************** ModuleIndex: TYPE = Table.Base RELATIVE POINTER [0..Table.Limit) TO ModuleRecord; nullModuleIndex: ModuleIndex = ModuleIndex.LAST; ModuleRecord: PUBLIC TYPE = MACHINE DEPENDENT RECORD [ mti: BcdDefs.MTIndex, includeMAIN: BOOL, unused: [0..2), cp: Tree.Index, -- code pack's parse tree node numWordPairsInProcArray: [1..4], -- if someProcs variant next: ModuleIndex, -- next module record in code pack's chain includeEV: BOOL, includeCatch: BOOL, link: ModuleIndex, -- links module records with same id hash values unused2: [0..2), procDescription: SELECT kind: * FROM allProcs => [], someProcs => [ -- up to PackageSymbols.MaxEntries procedures procIncluded: PACKED ARRAY [1..1) OF BOOL], ENDCASE]; MakeProcsLink: PROC [m: ModuleIndex] RETURNS [Tree.ProcsLink] = INLINE { RETURN [[literal[m]]]}; -- ***************** Module Record Location and Creation ***************** MRecHVSize: CARDINAL = 71; MRecHash: TYPE = [0..MRecHVSize); mRecHashVec: LONG POINTER TO MRecMap ← NIL; -- MRecHash -> ModuleIndex MRecMap: TYPE = RECORD [SEQUENCE length: CARDINAL OF ModuleIndex]; InitModuleHashVector: PROC = { mRecHashVec ← gd.zone.NEW[MRecMap[MRecHVSize]]; FOR i: MRecHash IN MRecHash DO mRecHashVec[i] ← nullModuleIndex ENDLOOP}; ReleaseModuleHashVector: PROC = { IF mRecHashVec # NIL THEN gd.zone.FREE[@mRecHashVec]}; HashForModule: PROC [module: BcdDefs.MTIndex] RETURNS [MRecHash] = { moduleName: BcdDefs.NameRecord = SourceBcd.bcdBases.mtb[module].name; moduleSS: String.SubString ← @moduleSSDesc; moduleSSDesc: String.SubStringDescriptor ← [ base: @SourceBcd.bcdBases.ssb.string, offset: moduleName, length: SourceBcd.bcdBases.ssb.size[moduleName]]; RETURN[HashValue[moduleSS]]}; HashValue: PROC [ss: String.SubString] RETURNS [MRecHash] = { CharMask: PROC [CHARACTER, WORD] RETURNS [CARDINAL] = LOOPHOLE[Inline.BITAND]; mask: WORD = 137B; -- masks out ASCII case shifts n: CARDINAL = ss.length; b: LONG STRING = ss.base; v: WORD; v ← CharMask[b[ss.offset], mask]*177B + CharMask[b[ss.offset+(n-1)], mask]; RETURN[Inline.BITXOR[v, n*17B] MOD MRecHVSize]}; -- one element cache for <MTIndex, cpNode> -> <ModuleIndex> mapping lastModule: BcdDefs.MTIndex ← BcdDefs.MTNull; lastCpNode: Tree.Index ← Tree.nullIndex; lastModuleIndex: ModuleIndex ← nullModuleIndex; moduleRecKind: TYPE = {all, some}; EnterModuleRec: PROC [ module: BcdDefs.MTIndex, cpNode: Tree.Index, procs: moduleRecKind] RETURNS [existingRec: ModuleIndex] = { existingRec ← FindModuleRec[ module: module, cpNode: cpNode, procs: procs, create: TRUE].m}; LocateExistingModuleRec: PROC [ module: BcdDefs.MTIndex, cpNode: Tree.Index] RETURNS [existingRec: ModuleIndex, found: BOOL] = { [existingRec, found] ← FindModuleRec[ module: module, cpNode: cpNode, procs: some, create: FALSE]}; FindModuleRec: PROC [ module: BcdDefs.MTIndex, cpNode: Tree.Index, procs: moduleRecKind, create: BOOL] RETURNS [m: ModuleIndex, found: BOOL] = { mHash: MRecHash; hashChainHead, moduleChainHead: ModuleIndex; IF cpNode = lastCpNode AND module = lastModule THEN RETURN[lastModuleIndex, TRUE]; -- found in cache mHash ← HashForModule[module]; hashChainHead ← mRecHashVec[mHash]; FOR m ← hashChainHead, mdb[m].link UNTIL m = nullModuleIndex DO IF mdb[m].mti = module AND mdb[m].cp = cpNode THEN { -- set up new cache entry lastModule ← module; lastCpNode ← cpNode; lastModuleIndex ← m; RETURN[m, TRUE]}; ENDLOOP; IF ~create THEN RETURN[nullModuleIndex, FALSE]; m ← (IF procs = all THEN NewAllProcsModuleRec[module, cpNode, hashChainHead] ELSE NewSomeProcsModuleRec[module, cpNode, hashChainHead]); mRecHashVec[mHash] ← m; -- add to hash chain -- add to code pack's module rec chain moduleChainHead ← NARROW[tb[cpNode].son[3], Tree.ProcsLink].index; IF moduleChainHead # nullModuleIndex THEN mdb[m].next ← moduleChainHead; tb[cpNode].son[3] ← MakeProcsLink[m]; lastModule ← module; lastCpNode ← cpNode; lastModuleIndex ← m; RETURN[m, FALSE]}; NewAllProcsModuleRec: PROC [ module: BcdDefs.MTIndex, cpNode: Tree.Index, chainHead: ModuleIndex] RETURNS [newRec: ModuleIndex] = { newRec ← table.Words[PackagerDefs.packmdtype, SIZE[allProcs ModuleRecord]]; mdb[newRec] ← ModuleRecord[ mti: module, includeMAIN: FALSE, unused: 0, cp: cpNode, numWordPairsInProcArray: 1, -- (irrelevant for allProcs variant) next: nullModuleIndex, includeEV: FALSE, includeCatch: FALSE, link: chainHead, unused2: 0, procDescription: allProcs[]]}; NewSomeProcsModuleRec: PROC [ module: BcdDefs.MTIndex, cpNode: Tree.Index, chainHead: ModuleIndex] RETURNS [newRec: ModuleIndex] = { numWordPairsInProcArray: [1..4] = SourceBcd.bcdBases.mtb[module].ngfi; newRec ← table.Words[ PackagerDefs.packmdtype, SIZE[someProcs ModuleRecord] + (2*numWordPairsInProcArray)]; mdb[newRec] ← ModuleRecord[ mti: module, includeMAIN: FALSE, unused: 0, cp: cpNode, numWordPairsInProcArray: numWordPairsInProcArray, next: nullModuleIndex, includeEV: FALSE, includeCatch: FALSE, link: chainHead, unused2: 0, procDescription: someProcs[procIncluded: ]]; WITH mdb[newRec] SELECT FROM someProcs => FOR i: CARDINAL IN [1..(32*numWordPairsInProcArray)) DO procIncluded[i] ← FALSE; ENDLOOP; ENDCASE}; -- ************************* Procedure Insertion ************************* -- information about each procedure, and MAIN, ENTRY VECTOR, and CATCH CODE proc: LONG POINTER TO ProcMap ← NIL; ProcMap: TYPE = ARRAY PackageSymbols.OPIndex OF ProcData; ProcData: TYPE = RECORD [ codePack: Tree.Index, -- proc was placed if (containing) codePack # nullIndex mark: BOOL]; -- used during EXCEPT processing InitProcMap: PROC = {proc ← gd.zone.NEW[ProcMap]}; ReleaseProcMap: PROC = { IF proc # NIL THEN gd.zone.FREE[@proc]}; InsertProc: PROC [opi: PackageSymbols.OPIndex, m: ModuleIndex] = { SELECT opi FROM OPMain => IF proc[OPMain].codePack # Tree.nullIndex --main already included-- THEN ReportProcIncludedTwice[ opi, mdb[m].mti, proc[OPMain].codePack, mdb[m].cp] ELSE {mdb[m].includeMAIN ← TRUE; proc[OPMain].codePack ← mdb[m].cp}; OPEntry => IF proc[OPEntry].codePack # Tree.nullIndex THEN ReportProcIncludedTwice[ opi, mdb[m].mti, proc[OPEntry].codePack, mdb[m].cp] ELSE {mdb[m].includeEV ← TRUE; proc[OPEntry].codePack ← mdb[m].cp}; OPCatch => IF proc[OPCatch].codePack # Tree.nullIndex THEN ReportProcIncludedTwice[ opi, mdb[m].mti, proc[OPCatch].codePack, mdb[m].cp] ELSE {mdb[m].includeCatch ← TRUE; proc[OPCatch].codePack ← mdb[m].cp}; ENDCASE => { IF opi = PackageSymbols.OPNull OR opi > lastOpi THEN CPerror[]; WITH mdb[m] SELECT FROM allProcs => ReportProcIncludedTwice[ opi, mdb[m].mti, proc[opi].codePack, mdb[m].cp]; someProcs => IF proc[opi].codePack # Tree.nullIndex THEN ReportProcIncludedTwice[ opi, mdb[m].mti, proc[opi].codePack, mdb[m].cp] ELSE {procIncluded[opi] ← TRUE; proc[opi].codePack ← mdb[m].cp}; ENDCASE}}; ReportProcIncludedTwice: PROC [ opi: PackageSymbols.OPIndex, mti: BcdDefs.MTIndex, cpNode1, cpNode2: Tree.Index] = { procIdSS: String.SubString ← @procIdSSDesc; procIdSSDesc: String.SubStringDescriptor; cpId1, cpId2: HashOps.HTIndex; SubStringForOPIndex[procIdSS, opi]; WITH tb[cpNode1].son[1] SELECT FROM hash => cpId1 ← index; ENDCASE => CPerror[]; WITH tb[cpNode2].son[1] SELECT FROM hash => cpId2 ← index; ENDCASE => CPerror[]; Error.ProcPlacedTwice[error, procIdSS, mti, cpId1, cpId2]}; SubStringForOPIndex: PUBLIC PROC [ ss: String.SubString, opi: PackageSymbols.OPIndex] = { SELECT opi FROM OPMain => {ss.base ← "MAIN"; ss.offset ← 0; ss.length ← 4}; OPEntry => {ss.base ← "ENTRY VECTOR"; ss.offset ← 0; ss.length ← 12}; OPCatch => {ss.base ← "CATCH CODE"; ss.offset ← 0; ss.length ← 10}; ENDCASE => { hti: Symbols.HTIndex = ModuleSymbols.outerPackArray[opi].hti; IF hti = Symbols.HTNull THEN { ss.base ← "(unknown)"; ss.offset ← 0; ss.length ← 9} ELSE SymbolOps.SubStringForHash[ss, hti]}}; -- ******************* Code Pack Procedure Determination ******************** codePackProcsDetermined: BOOL ← FALSE; Determine: PUBLIC PROC [configTreeRoot: SourceBcd.CTreeIndex] = { ENABLE UNWIND => Destroy[]; IF codePackProcsDetermined THEN CPerror[]; gd ← PackagerDefs.globalData; table ← gd.ownTable; table.AddNotify[UpdateBases]; InitModuleHashVector[]; InitProcMap[]; PlaceProcedures[configTreeRoot]; ValidatePackagingDesc[]; codePackProcsDetermined ← TRUE}; Destroy: PUBLIC PROC = { ReleaseModuleHashVector[]; ReleaseProcMap[]; IF table # NIL THEN {table.DropNotify[UpdateBases]; table ← NIL}; gd ← NIL; codePackProcsDetermined ← FALSE}; PlaceProcedures: PROC [configTreeRoot: SourceBcd.CTreeIndex] = INLINE { SourceBcd.EnumerateModulesInConfig[ kind: prototype, configTreeNode: configTreeRoot, userProc: PlaceOneModulesProcs]}; lastOpi: PackageSymbols.OPIndex ← 0; hasCatchCode: BOOL ← TRUE; PlaceOneModulesProcs: PROC [module: BcdDefs.MTIndex] RETURNS [stop: BOOL] = { PlaceOneCDNodesProcs: PROC [cdNode: Tree.Index] RETURNS [stop: BOOL] = { PlaceModulesProcsForOneCDNode[module, cdNode]; RETURN[FALSE]}; IF ProcessingOrder.IsEmpty[module] THEN { name: BcdDefs.NameRecord = SourceBcd.bcdBases.mtb[module].name; Error.ErrorName[error, "was never placed in a code segment"L, name]; RETURN[FALSE]}; IF ~SourceBcd.IsTableCompiled[module] THEN { -- load module's symbol table ModuleSymbols.Load[module ! ModuleSymbols.InvalidSymbols => GO TO badSymbols]; BEGIN ENABLE UNWIND => ModuleSymbols.Unload[]; lastOpi ← (LENGTH[ModuleSymbols.outerPackArray] - 2); hasCatchCode ← (ModuleSymbols.outerPackArray[lastOpi+1].length # 0); MarkProcsUnplaced[]; ProcessingOrder.Enumerate[module, PlaceOneCDNodesProcs]; VerifyProcsAllPlaced[module]; ModuleSymbols.Unload[]; END} ELSE { -- table compiled: don't load symbols hasCatchCode ← FALSE; ProcessingOrder.Enumerate[module, PlaceOneCDNodesProcs]}; RETURN[FALSE]; EXITS badSymbols => { name: BcdDefs.NameRecord = SourceBcd.bcdBases.mtb[module].name; Error.ErrorName[error, "has invalid symbols"L, name]; RETURN[FALSE]}}; MarkProcsUnplaced: PROC = { FOR opi: PackageSymbols.OPIndex IN PackageSymbols.OPIndex DO proc[opi] ← [codePack: Tree.nullIndex, mark: FALSE]; ENDLOOP}; VerifyProcsAllPlaced: PROC [module: BcdDefs.MTIndex] = { NotPlaced: PROC [opi: PackageSymbols.OPIndex] = { procIdSS: String.SubStringDescriptor; SubStringForOPIndex[@procIdSS, opi]; Error.ProcNotPlaced[error, @procIdSS, module]}; IF proc[OPMain].codePack = Tree.nullIndex THEN NotPlaced[OPMain]; IF proc[OPEntry].codePack = Tree.nullIndex THEN NotPlaced[OPEntry]; IF proc[OPCatch].codePack = Tree.nullIndex AND hasCatchCode THEN NotPlaced[OPCatch]; FOR opi: PackageSymbols.OPIndex IN [1..lastOpi] DO IF proc[opi].codePack = Tree.nullIndex THEN NotPlaced[opi]; ENDLOOP}; PlaceModulesProcsForOneCDNode: PROC [ module: BcdDefs.MTIndex, cdNode: Tree.Index] = { saveIndex: CARDINAL = gd.textIndex; gd.textIndex ← tb[cdNode].info; SELECT tb[cdNode].name FROM allComp => PlaceAllCompCDProcs[module, cdNode]; compItems => PlaceCompItemsCDProcs[module, cdNode]; exceptItems => PlaceExceptItemsCDProcs[module, cdNode]; exceptPacks => PlaceExceptPacksCDProcs[module, cdNode]; itemsExceptPacks => PlaceItemsExceptPacksCDProcs[module, cdNode]; exceptPacksItems => PlaceExceptPacksItemsCDProcs[module, cdNode]; mainOfPL, evOfPL, catchOfPL => PlaceMiscCodeForCD[module, cdNode]; ENDCASE => CPerror[]; gd.textIndex ← saveIndex}; --****** Place Module's Procedures For Explicit Component Descriptions ****** PlaceAllCompCDProcs: PROC [module: BcdDefs.MTIndex, cdNode: Tree.Index] = { -- ComponentDesc ::= Component InsertWholeModule[module: module, cpNode: tb[cdNode].cp]}; InsertWholeModule: PROC [module: BcdDefs.MTIndex, cpNode: Tree.Index] = { m: ModuleIndex; IF LocateExistingModuleRec[module, cpNode].found THEN { Error.ModuleAlreadyPacked[error, module]; RETURN}; m ← EnterModuleRec[module: module, cpNode: cpNode, procs: all]; IF ~SourceBcd.IsTableCompiled[module] THEN { IF ~tb[cpNode].attrs[$exceptMAIN] THEN InsertProc[OPMain, m]; IF ~tb[cpNode].attrs[$exceptEV] THEN InsertProc[OPEntry, m]; IF ~tb[cpNode].attrs[$exceptCatch] THEN InsertProc[OPCatch, m]; FOR opi: PackageSymbols.OPIndex IN [1..lastOpi] DO proc[opi].codePack ← cpNode; ENDLOOP}}; PlaceCompItemsCDProcs: PROC [module: BcdDefs.MTIndex, cdNode: Tree.Index] = { -- ComponentDesc ::= Component [ItemList] WITH tb[cdNode].son[1] SELECT FROM symbol => { componentSE: SemanticEntry.STIndex = index; WITH stb[componentSE] SELECT FROM module => { IF mti # module THEN CPerror[]; InsertNamedProcsFromModule[ module: module, cpNode: tb[cdNode].cp, itemList: tb[cdNode].son[2]]}; config => -- ProcessingOrderImpl found module should be processed InsertWholeModule[module: module, cpNode: tb[cdNode].cp]; ENDCASE}; ENDCASE => CPerror[]}; InsertNamedProcsFromModule: PROC [ module: BcdDefs.MTIndex, cpNode: Tree.Index, itemList: Tree.Link] = { procSS: String.SubString ← @procSSDesc; procSSDesc: String.SubStringDescriptor; opi: PackageSymbols.OPIndex; m: ModuleIndex; InsertOneProc: Tree.Scan = { WITH t SELECT FROM hash => { procId: HashOps.HTIndex = index; HashOps.SubStringForHash[procSS, procId]; opi ← ModuleSymbols.FindProc[procSS]; IF opi = PackageSymbols.OPNull THEN Error.NotProcInModule[error, procId, module] ELSE InsertProc[opi, m]}; subtree => { itemNode: Tree.Index = index; SELECT tb[itemNode].name FROM main => { IF tb[cpNode].attrs[$exceptMAIN] THEN { Error.Error[warning, "MAIN is included in a code pack for which EXCEPT[MAIN] was specified"L]; RETURN}; InsertProc[OPMain, m]}; ev => { IF tb[cpNode].attrs[$exceptEV] THEN { Error.Error[warning, "ENTRY VECTOR is included in a code pack for which EXCEPT[ENTRY VECTOR] was specified"L]; RETURN}; InsertProc[OPEntry, m]}; catch => { IF tb[cpNode].attrs[$exceptCatch] THEN { Error.Error[warning, "CATCH CODE is included in a code pack for which EXCEPT[CATCH CODE] was specified"L]; RETURN}; InsertProc[OPCatch, m]}; ENDCASE => CPerror[]}; ENDCASE => CPerror[]}; m ← EnterModuleRec[module: module, cpNode: cpNode, procs: some]; TreeOps.ScanList[itemList, InsertOneProc]}; PlaceExceptItemsCDProcs: PROC [module: BcdDefs.MTIndex, cdNode: Tree.Index] = { -- ComponentDesc ::= Component EXCEPT [ItemList] WITH tb[cdNode].son[1] SELECT FROM symbol => { componentSE: SemanticEntry.STIndex = index; WITH stb[componentSE] SELECT FROM module => { IF mti # module THEN CPerror[]; ExcludeNamedProcsFromModule[ module: module, cpNode: tb[cdNode].cp, itemList: tb[cdNode].son[2]]}; config => -- ProcessingOrderImpl found module should be output InsertWholeModule[module: module, cpNode: tb[cdNode].cp]; ENDCASE}; ENDCASE => CPerror[]}; ExcludeNamedProcsFromModule: PROC [ module: BcdDefs.MTIndex, cpNode: Tree.Index, itemList: Tree.Link] = { m: ModuleIndex = EnterModuleRec[module: module, cpNode: cpNode, procs: some]; RemoveMarkOfNamedProc: Tree.Scan = { WITH t SELECT FROM hash => { procId: HashOps.HTIndex = index; procSS: String.SubString ← @procSSDesc; procSSDesc: String.SubStringDescriptor; opi: PackageSymbols.OPIndex; HashOps.SubStringForHash[procSS, procId]; opi ← ModuleSymbols.FindProc[procSS]; IF opi = PackageSymbols.OPNull THEN Error.NotProcInModule[error, procId, module] ELSE WITH mdb[m] SELECT FROM someProcs => proc[opi].mark ← FALSE; ENDCASE}; subtree => { itemNode: Tree.Index = index; SELECT tb[itemNode].name FROM main => proc[OPMain].mark ← FALSE; ev => proc[OPEntry].mark ← FALSE; catch => proc[OPCatch].mark ← FALSE; ENDCASE => CPerror[]}; ENDCASE => CPerror[]}; MarkAllProcs[m]; -- then remove marks for those procs to exclude IF tb[cpNode].attrs[$exceptMAIN] THEN proc[OPMain].mark ← FALSE; IF tb[cpNode].attrs[$exceptEV] THEN proc[OPEntry].mark ← FALSE; IF tb[cpNode].attrs[$exceptCatch] THEN proc[OPCatch].mark ← FALSE; TreeOps.ScanList[itemList, RemoveMarkOfNamedProc]; InsertRemainingMarkedProcs[m]}; MarkAllProcs: PROC [m: ModuleIndex] = { WITH mdb[m] SELECT FROM allProcs => Error.ModuleAlreadyPacked[error, mdb[m].mti]; someProcs => { proc[OPMain].mark ← TRUE; proc[OPEntry].mark ← TRUE; proc[OPCatch].mark ← TRUE; FOR opi: PackageSymbols.OPIndex IN [1..lastOpi] DO proc[opi].mark ← TRUE; ENDLOOP}; ENDCASE}; InsertRemainingMarkedProcs: PROC [m: ModuleIndex] = { IF proc[OPMain].mark THEN InsertProc[OPMain, m]; -- wasn't excluded IF proc[OPEntry].mark THEN InsertProc[OPEntry, m]; IF proc[OPCatch].mark THEN InsertProc[OPCatch, m]; FOR opi: PackageSymbols.OPIndex IN [1..lastOpi] DO IF proc[opi].mark THEN InsertProc[opi, m]; ENDLOOP}; --****** Place Module's Procedures For Implicit Component Descriptions ****** PlaceExceptPacksCDProcs: PROC [module: BcdDefs.MTIndex, cdNode: Tree.Index] = { -- ComponentDesc ::= Component EXCEPT PackList WITH tb[cdNode].son[1] SELECT FROM symbol => { componentSE: SemanticEntry.STIndex = index; WITH stb[componentSE] SELECT FROM module => { IF mti # module THEN CPerror[]; IncludeAllProcsNotInAnyPack[ module: module, cpNode: tb[cdNode].cp, packList: tb[cdNode].son[2]]}; config => -- ProcessingOrderImpl found module should be processed IncludeAllProcsNotInAnyPack[ module: module, cpNode: tb[cdNode].cp, packList: tb[cdNode].son[2]]; ENDCASE}; ENDCASE => CPerror[]}; IncludeAllProcsNotInAnyPack: PROC [ module: BcdDefs.MTIndex, cpNode: Tree.Index, packList: Tree.Link] = { -- include all procs not already in a code pack of packList m: ModuleIndex; found: BOOL; RemoveMarksOfProcsInOnePack: Tree.Scan = { RemoveMarkOfOneProc: PROC [opi: PackageSymbols.OPIndex] RETURNS [BOOL] = { proc[opi].mark ← FALSE; RETURN[FALSE]}; WITH t SELECT FROM symbol => { cpSE: SemanticEntry.STIndex = index; oldMRec: ModuleIndex; WITH stb[cpSE] SELECT FROM codePack => { [oldMRec, found] ← LocateExistingModuleRec[ module: module, cpNode: treeNode]; IF found THEN -- procs from module in old cp EnumerateProcs[oldMRec, RemoveMarkOfOneProc]}; ENDCASE}; ENDCASE => CPerror[]}; IF SourceBcd.IsTableCompiled[module] THEN { [m, found] ← LocateExistingModuleRec[module: module, cpNode: cpNode]; IF ~found THEN InsertWholeModule[module: module, cpNode: cpNode] ELSE Error.TableCompModuleNotIncAsUnit[error, module]} ELSE { m ← EnterModuleRec[module: module, cpNode: cpNode, procs: some]; MarkAllProcs[m]; -- then remove marks for those procs to exclude IF tb[cpNode].attrs[$exceptMAIN] THEN proc[OPMain].mark ← FALSE; IF tb[cpNode].attrs[$exceptEV] THEN proc[OPEntry].mark ← FALSE; IF tb[cpNode].attrs[$exceptCatch] THEN proc[OPCatch].mark ← FALSE; TreeOps.ScanList[packList, RemoveMarksOfProcsInOnePack]; InsertRemainingMarkedProcs[m]}}; PlaceItemsExceptPacksCDProcs: PROC [ module: BcdDefs.MTIndex, cdNode: Tree.Index] = { -- ComponentDesc ::= Component [ItemList] EXCEPT PackList WITH tb[cdNode].son[1] SELECT FROM symbol => { componentSE: SemanticEntry.STIndex = index; WITH stb[componentSE] SELECT FROM -- component must not be a module config => -- ProcessingOrderImpl found module should be processed IncludeAllProcsNotInAnyPack[ module: module, cpNode: tb[cdNode].cp, packList: tb[cdNode].son[3]]; ENDCASE}; ENDCASE => CPerror[]}; PlaceExceptPacksItemsCDProcs: PROC [ module: BcdDefs.MTIndex, cdNode: Tree.Index] = { -- ComponentDesc ::= Component EXCEPT PackList, [ItemList] WITH tb[cdNode].son[1] SELECT FROM symbol => { componentSE: SemanticEntry.STIndex = index; WITH stb[componentSE] SELECT FROM module => { IF mti # module THEN CPerror[]; IncludeProcsNotInPackNorItemLists[ module: module, cpNode: tb[cdNode].cp, packList: tb[cdNode].son[2], itemList: tb[cdNode].son[3]]}; config => -- ProcessingOrderImpl found module should be processed IncludeAllProcsNotInAnyPack[ module: module, cpNode: tb[cdNode].cp, packList: tb[cdNode].son[2]]; ENDCASE}; ENDCASE => CPerror[]}; IncludeProcsNotInPackNorItemLists: PROC [ module: BcdDefs.MTIndex, cpNode: Tree.Index, packList: Tree.Link, itemList: Tree.Link] = { -- include all procs not already in a code pack or in item list m: ModuleIndex = EnterModuleRec[module: module, cpNode: cpNode, procs: some]; found: BOOL; RemoveMarksOfProcsInOnePack: Tree.Scan = { RemoveMarkOfOneProcInPack: PROC [ opi: PackageSymbols.OPIndex] RETURNS [stop: BOOL] = { proc[opi].mark ← FALSE; RETURN[FALSE]}; WITH t SELECT FROM symbol => { cpSE: SemanticEntry.STIndex = index; oldMRec: ModuleIndex; WITH stb[cpSE] SELECT FROM codePack => { [oldMRec, found] ← LocateExistingModuleRec[ module: module, cpNode: treeNode]; IF found THEN -- procs from module in old cp EnumerateProcs[oldMRec, RemoveMarkOfOneProcInPack]}; ENDCASE}; ENDCASE => CPerror[]}; RemoveMarkOfOneProc: Tree.Scan = { WITH t SELECT FROM hash => { procId: HashOps.HTIndex = index; procSS: String.SubString ← @procSSDesc; procSSDesc: String.SubStringDescriptor; opi: PackageSymbols.OPIndex; HashOps.SubStringForHash[procSS, procId]; opi ← ModuleSymbols.FindProc[procSS]; IF opi = PackageSymbols.OPNull THEN Error.NotProcInModule[error, procId, module] ELSE proc[opi].mark ← FALSE}; subtree => { itemNode: Tree.Index = index; SELECT tb[itemNode].name FROM main => proc[OPMain].mark ← FALSE; ev => proc[OPEntry].mark ← FALSE; catch => proc[OPCatch].mark ← FALSE; ENDCASE => CPerror[]}; ENDCASE => CPerror[]}; MarkAllProcs[m]; -- then remove marks for those procs to exclude IF tb[cpNode].attrs[$exceptMAIN] THEN proc[OPMain].mark ← FALSE; IF tb[cpNode].attrs[$exceptEV] THEN proc[OPEntry].mark ← FALSE; IF tb[cpNode].attrs[$exceptCatch] THEN proc[OPCatch].mark ← FALSE; TreeOps.ScanList[packList, RemoveMarksOfProcsInOnePack]; TreeOps.ScanList[itemList, RemoveMarkOfOneProc]; InsertRemainingMarkedProcs[m]}; --**** Place Module's Procedures For MAIN/ENTRY VECTOR/CATCH CODE OF CDs **** PlaceMiscCodeForCD: PROC [module: BcdDefs.MTIndex, cdNode: Tree.Index] = { -- ComponentDesc ::= MAIN OF PackList -- ComponentDesc ::= ENTRY VECTOR OF PackList -- ComponentDesc ::= CATCH CODE OF PackList -- add module's main proc/ev/catch code if any of its other procs in packlist packList: Tree.Link = tb[cdNode].son[1]; firstInList: Tree.Link; miscCodeOpi: PackageSymbols.OPIndex = (SELECT tb[cdNode].name FROM mainOfPL => OPMain, evOfPL => OPEntry, ENDCASE --catchOfPL-- => OPCatch); EnterMiscCodeIfOtherProcsInASegmentsPack: Tree.Test = { WITH t SELECT FROM subtree => { segsCpNode: Tree.Index = index; inserted: BOOL = InsertMiscCodeIfOtherProcsInPack[ module: module, cpNode: tb[cdNode].cp, miscCodeOpi: miscCodeOpi, existingCpNode: segsCpNode]; RETURN[inserted]}; -- stop enumeration if main/ev/catch code inserted ENDCASE => CPerror[]; RETURN[FALSE]}; EnterMiscCodeIfOtherProcsInOnePack: Tree.Test = { WITH t SELECT FROM symbol => { cpSE: SemanticEntry.STIndex = index; WITH stb[cpSE] SELECT FROM codePack => { inserted: BOOL = InsertMiscCodeIfOtherProcsInPack[ module: module, cpNode: tb[cdNode].cp, miscCodeOpi: miscCodeOpi, existingCpNode: treeNode]; RETURN[inserted]}; -- stop if main/ev/catch code inserted ENDCASE}; ENDCASE => CPerror[]; RETURN[FALSE]}; IF SourceBcd.IsTableCompiled[module] THEN RETURN; IF TreeOps.ListLength[packList] = 1 THEN { -- packlist might only be name of current code segment firstInList ← TreeOps.ListHead[packList]; WITH firstInList SELECT FROM symbol => { firstSE: SemanticEntry.STIndex = index; WITH stb[firstSE] SELECT FROM segment => { segNode: Tree.Index = treeNode; -- the current segment TreeOps.SearchList[ tb[segNode].son[2], EnterMiscCodeIfOtherProcsInASegmentsPack]; RETURN}; ENDCASE}; ENDCASE => CPerror[]}; TreeOps.SearchList[packList, EnterMiscCodeIfOtherProcsInOnePack]}; InsertMiscCodeIfOtherProcsInPack: PROC [ module: BcdDefs.MTIndex, cpNode: Tree.Index, miscCodeOpi: PackageSymbols.OPIndex, existingCpNode: Tree.Index] RETURNS [inserted: BOOL] = { -- insert module's main/ev/catch code if it has other procs in existingCpNode existingMRec, newMRec: ModuleIndex; found: BOOL; [existingMRec, found] ← LocateExistingModuleRec[ module: module, cpNode: existingCpNode]; IF found THEN { newMRec ← EnterModuleRec[module: module, cpNode: cpNode, procs: some]; InsertProc[miscCodeOpi, newMRec]; RETURN[TRUE]} ELSE RETURN[FALSE]}; --********* Validate packaging description ********* -- For each code pack, check that -- (1) it is nonempty, and -- (2) procedures were included from each module, and -- For each module, check that -- (1) the entry vector precedes any procedure and catch code evPlaced: LONG POINTER TO EVPlacedMap ← NIL; -- SourceBcd.ModuleNum -> BOOL EVPlacedMap: TYPE = RECORD [SEQUENCE length: CARDINAL OF BOOL]; ValidatePackagingDesc: PROC [] = { ENABLE UNWIND => ReleaseEVPlacedArray[]; InitEVPlacedArray[]; EnumerateSegments[CheckOneCodeSegment]; ReleaseEVPlacedArray[]}; InitEVPlacedArray: PROC = { evPlaced ← gd.zone.NEW[EVPlacedMap[SourceBcd.moduleCount]]; FOR i: SourceBcd.ModuleNum IN [0..SourceBcd.moduleCount) DO evPlaced[i] ← FALSE; ENDLOOP}; ReleaseEVPlacedArray: PROC = { IF evPlaced # NIL THEN gd.zone.FREE[@evPlaced]}; CheckOneCodeSegment: PROC [segNode: Tree.Index] RETURNS [stop: BOOL] = { IF segNode # Tree.nullIndex THEN EnumerateCodePacks[segNode, CheckOneCodePack]; RETURN[FALSE]}; currentCPId: HashOps.HTIndex; cpEmpty, discardCP: BOOL; CheckOneCodePack: PROC [cpNode: Tree.Index] RETURNS [stop: BOOL] = { IF cpNode # Tree.nullIndex THEN { WITH tb[cpNode].son[1] SELECT FROM hash => currentCPId ← index; ENDCASE; discardCP ← IsDiscardCodePack[cpNode]; cpEmpty ← TRUE; EnumerateModules[cpNode, CheckOneCodePackModule]; IF cpEmpty THEN Error.EmptyCodePack[error, currentCPId]}; RETURN[FALSE]}; currentMti: BcdDefs.MTIndex; currentModuleNum: SourceBcd.ModuleNum; CheckOneCodePackModule: PROC [ mti: BcdDefs.MTIndex, module: CodePackProcs.ModuleIndex] RETURNS [stop: BOOL] = { IF SourceBcd.IsTableCompiled[mti] THEN cpEmpty ← FALSE ELSE IF AnyProcs[module] THEN { cpEmpty ← FALSE; currentMti ← mti; currentModuleNum ← SourceBcd.ModuleNumForMti[mti]; EnumerateProcs[module, CheckOneProc]} ELSE Error.NoProcFromModuleInCP[warning, mti, currentCPId]; RETURN[FALSE]}; CheckOneProc: PROC [opi: PackageSymbols.OPIndex] RETURNS [stop: BOOL] = { SELECT opi FROM OPEntry => { IF discardCP THEN { Error.EVInDiscardCodePack[error, currentMti]; RETURN[TRUE]}; evPlaced[currentModuleNum] ← TRUE}; OPCatch => IF hasCatchCode AND ~evPlaced[currentModuleNum] THEN { Error.EVNotFirst[error, currentMti]; RETURN[TRUE]}; ENDCASE => IF ~evPlaced[currentModuleNum] THEN { Error.EVNotFirst[error, currentMti]; RETURN[TRUE]}; RETURN[FALSE]}; --******************** Code Pack Procedure Enumeration ********************** EnumerateSegments: PUBLIC PROC [ userProc: PROC [segNode: Tree.Index] RETURNS [stop: BOOL]] = { OutputOneCodeSegment: Tree.Test = { WITH t SELECT FROM subtree => { treeNode: Tree.Index = index; SELECT tb[treeNode].name FROM codeSeg, merge => IF ~tb[treeNode].attrs[$superceded] THEN { IF userProc[treeNode] THEN RETURN[TRUE]}; -- stop enumeration ENDCASE}; ENDCASE => CPerror[]; RETURN[FALSE]}; TreeOps.SearchList[gd.root, OutputOneCodeSegment]}; SubStringForSegmentNode: PUBLIC PROC [ ss: String.SubString, segNode: Tree.Index] = { WITH tb[segNode].son[1] SELECT FROM hash => { segmentHti: HashOps.HTIndex = index; HashOps.SubStringForHash[ss, segmentHti]}; ENDCASE => CPerror[]}; EnumerateCodePacks: PUBLIC PROC [ segNode: Tree.Index, userProc: PROC [cpNode: Tree.Index] RETURNS [stop: BOOL]] = { saveIndex: CARDINAL = gd.textIndex; OutputOneCodePack: Tree.Test = { WITH t SELECT FROM subtree => { cpNode: Tree.Index = index; SELECT tb[cpNode].name FROM codePack, unnamedCodePack, discardCodePack => { IF tb[cpNode].attrs[$superceded] THEN CPerror[]; IF userProc[cpNode] THEN RETURN[TRUE]}; -- stop enumeration ENDCASE => CPerror[]}; ENDCASE => CPerror[]; RETURN[FALSE]}; gd.textIndex ← tb[segNode].info; IF tb[segNode].attrs[$superceded] THEN CPerror[]; TreeOps.SearchList[tb[segNode].son[2], OutputOneCodePack]; gd.textIndex ← saveIndex}; SubStringForCodePackNode: PUBLIC PROC [ ss: String.SubString, cpNode: Tree.Index] = { WITH tb[cpNode].son[1] SELECT FROM hash => { codePackHti: HashOps.HTIndex = index; HashOps.SubStringForHash[ss, codePackHti]}; ENDCASE => CPerror[]}; HtiForCodePackNode: PUBLIC PROC [ cpNode: Tree.Index] RETURNS [hti: HashOps.HTIndex] = { WITH tb[cpNode].son[1] SELECT FROM hash => {hti ← index; RETURN[hti]}; ENDCASE => CPerror[]}; IsDiscardCodePack: PUBLIC PROC [cpNode: Tree.Index] RETURNS [yes: BOOL] = { IF cpNode = Tree.nullIndex THEN CPerror[]; RETURN[ tb[cpNode].name = discardCodePack ]}; DoneEnumeratingModules: SIGNAL = CODE; EnumerateModules: PUBLIC PROC [ cpNode: Tree.Index, userProc: PROC [ mti: BcdDefs.MTIndex, module: ModuleIndex] RETURNS [stop: BOOL]] = { saveIndex: CARDINAL = gd.textIndex; gd.textIndex ← tb[cpNode].info; IF tb[cpNode].attrs[$superceded] THEN CPerror[]; -- code pack has been superceded OutputModules[ cpNode: cpNode, userProc: userProc ! DoneEnumeratingModules => CONTINUE]; gd.textIndex ← saveIndex}; OutputModules: PROC [ -- called recursively when multiple layers of merging cpNode: Tree.Index, userProc: PROC [ mti: BcdDefs.MTIndex, module: ModuleIndex] RETURNS [stop: BOOL]] = { SELECT tb[cpNode].name FROM codePack, unnamedCodePack, discardCodePack => { cdList: Tree.Link = tb[cpNode].son[2]; firstCdLink: Tree.Link = TreeOps.ListHead[cdList]; WITH firstCdLink SELECT FROM symbol => -- cpNode is a code pack in a merged code segment OutputModulesOfMergedOldCodePacks[ oldCpList: cdList, userProc: userProc]; ENDCASE => -- cpNode is a "normal" code pack OutputCodePackModules[ moduleList: tb[cpNode].son[3], userProc: userProc]}; ENDCASE => CPerror[]}; OutputModulesOfMergedOldCodePacks: PROC [ oldCpList: Tree.Link, userProc: PROC [ mti: BcdDefs.MTIndex, module: ModuleIndex] RETURNS [stop: BOOL]] = { OutputModulesOfOneOldCodePack: Tree.Scan = { WITH t SELECT FROM symbol => { oldCpSE: SemanticEntry.STIndex = index; WITH stb[oldCpSE] SELECT FROM codePack => { oldCpNode: Tree.Index = treeNode; OutputModules[cpNode: oldCpNode, userProc: userProc]}; ENDCASE}; ENDCASE => CPerror[]}; TreeOps.ScanList[oldCpList, OutputModulesOfOneOldCodePack]}; OutputCodePackModules: PROC [ moduleList: Tree.Link, userProc: PROC [ mti: BcdDefs.MTIndex, module: ModuleIndex] RETURNS [stop: BOOL]] = { moduleChainHead: ModuleIndex = NARROW[moduleList, Tree.ProcsLink].index; FOR m: ModuleIndex ← moduleChainHead, mdb[m].next UNTIL m = nullModuleIndex DO mti: BcdDefs.MTIndex = mdb[m].mti; stopEnumeration: BOOL; IF ~SourceBcd.IsTableCompiled[mti] THEN { ModuleSymbols.Load[mti ! ModuleSymbols.InvalidSymbols => LOOP]; lastOpi ← (LENGTH[ModuleSymbols.outerPackArray] - 2); hasCatchCode ← (ModuleSymbols.outerPackArray[lastOpi+1].length # 0); stopEnumeration ← userProc[mti, m ! UNWIND => ModuleSymbols.Unload[]]; ModuleSymbols.Unload[]; IF stopEnumeration THEN SIGNAL DoneEnumeratingModules} ELSE { -- table compiled: don't load symbol table hasCatchCode ← FALSE; IF userProc[mti, m] THEN SIGNAL DoneEnumeratingModules}; ENDLOOP}; AnyProcs: PUBLIC PROC [module: ModuleIndex] RETURNS [reply: BOOL] = { -- return TRUE if any procedures are specified by a ModuleRecord IF SourceBcd.IsTableCompiled[mdb[module].mti] THEN RETURN[FALSE]; IF mdb[module].includeMAIN THEN RETURN[TRUE]; IF mdb[module].includeEV THEN RETURN[TRUE]; IF mdb[module].includeCatch THEN RETURN[TRUE]; WITH mdb[module] SELECT FROM allProcs => RETURN[TRUE]; someProcs => FOR p: PackageSymbols.OPIndex IN [1..lastOpi] DO IF procIncluded[p] THEN RETURN[TRUE]; ENDLOOP; ENDCASE => CPerror[]; RETURN[FALSE]}; EnumerateProcs: PUBLIC PROC [ module: ModuleIndex, userProc: PROC [proc: PackageSymbols.OPIndex] RETURNS [stop: BOOL]] = { IF SourceBcd.IsTableCompiled[mdb[module].mti] THEN RETURN; IF mdb[module].includeEV THEN IF userProc[OPEntry] THEN RETURN; IF mdb[module].includeMAIN THEN IF userProc[OPMain] THEN RETURN; WITH mdb[module] SELECT FROM allProcs => { FOR p: PackageSymbols.OPIndex IN [1..lastOpi] DO IF userProc[p] THEN RETURN; ENDLOOP}; someProcs => { FOR p: PackageSymbols.OPIndex IN [1..lastOpi] DO IF procIncluded[p] THEN IF userProc[p] THEN RETURN; ENDLOOP}; ENDCASE => CPerror[]; IF mdb[module].includeCatch THEN [] ← userProc[OPCatch]}; END.