-- file SymbolCopier.mesa -- last modified by Satterthwaite, May 12, 1983 10:35 am DIRECTORY Alloc: TYPE USING [Handle, Notifier, AddNotify, DropNotify, Top, Words], Copier: TYPE USING [FindMdEntry, FreeSymbolTable, GetSymbolTable], Inline: TYPE USING [LongDivMod, LongMult], Literals: TYPE USING [STNull], LiteralOps: TYPE USING [CopyLiteral], OSMiscOps: TYPE USING [FreeWords, Words], Strings: TYPE USING [SubString, SubStringDescriptor], SymbolTable: TYPE USING [Base], Symbols: TYPE, SymbolOps: TYPE USING [ EnterExtension, EnterString, FirstCtxSe, LinkBti, MakeCtxSe, MakeNonCtxSe, MakeSeChain, NewCtx, NextSe, ParentBti, RCType, ResetCtxList, SearchContext, SetSeLink, SubStringForName, UnderType], SymbolPack: TYPE, Tree: TYPE USING [Base, Index, Link, Map, Scan, Null, NullIndex, treeType], TreeOps: TYPE USING [ CopyTree, FreeNode, GetNode, OpName, PopTree, PushNode, PushTree, ScanList, SetAttr, SetInfo]; SymbolCopier: PROGRAM IMPORTS Alloc, Copier, Inline, LiteralOps, OSMiscOps, TreeOps, ownSymbols: SymbolPack, SymbolOps EXPORTS Copier = { OPEN SymbolOps, Symbols; -- tables defining the current symbol table table: Alloc.Handle; seb: Symbols.Base; -- se table ctxb: Symbols.Base; -- context table mdb: Symbols.Base; -- module directory base bb: Symbols.Base; -- body table tb: Tree.Base; -- tree table CopierNotify: Alloc.Notifier = { -- called whenever the main symbol table is repacked seb _ base[seType]; ctxb _ base[ctxType]; mdb _ base[mdType]; bb _ base[bodyType]; tb _ base[Tree.treeType]; IF iBase # NIL AND iBase = ownSymbols THEN INotify[]}; -- table bases for the current include module iBase: SymbolTable.Base; iHt: LONG DESCRIPTOR FOR ARRAY HTIndex OF HTRecord; iSeb: Symbols.Base; iCtxb: Symbols.Base; INotify: PROC = { -- called whenever iBase switches or tables moved iHt _ iBase.ht; iSeb _ iBase.seb; iCtxb _ iBase.ctxb}; MemoCacheSize: CARDINAL = 509; -- prime < 512 SearchCache: TYPE = ARRAY [0..MemoCacheSize) OF RECORD[ hti: HTIndex, ctx: CTXIndex]; memoCache: LONG POINTER TO SearchCache; -- initialization/finalization CopierInit: PUBLIC PROC [ ownTable: Alloc.Handle, symbolCachePages: CARDINAL, useMemo: BOOL] = { iBase _ NIL; table _ ownTable; table.AddNotify[CopierNotify]; IF useMemo THEN { memoCache _ OSMiscOps.Words[SearchCache.SIZE]; memoCache^ _ ALL[ [hti:HTNull, ctx:CTXNull] ]; typeCache _ OSMiscOps.Words[TypeCache.SIZE]; typeCache^ _ ALL[ [mdi:MDNull, iSei:SENull, sei: SENull] ]} ELSE {memoCache _ NIL; typeCache _ NIL}; currentBody _ BTNull}; ResetCaches: PROC = INLINE { -- see ResetIncludeContexts IF typeCache # NIL THEN OSMiscOps.FreeWords[typeCache]; IF memoCache # NIL THEN OSMiscOps.FreeWords[memoCache]}; CopierReset: PUBLIC PROC = { ResetIncludeContexts[]; table.DropNotify[CopierNotify]; table _ NIL}; -- manipulation of symbol tokens (without copying) SEToken: PUBLIC TYPE = RECORD[ISEIndex]; nullSEToken: PUBLIC SEToken _ [ISENull]; CtxValue: PUBLIC PROC [ctx: CTXIndex, value: CARDINAL] RETURNS [t: SEToken] = { mdi: MDIndex; iCtx: CTXIndex; [mdi, iCtx] _ InverseMapCtx[ctx]; IF OpenIncludedTable[mdi] THEN { t _ [iBase.SeiForValue[value, iCtx]]; CloseIncludedTable[]} ELSE t _ nullSEToken; RETURN}; CtxFirst: PUBLIC PROC [ctx: CTXIndex] RETURNS [t: SEToken] = { mdi: MDIndex; iCtx: CTXIndex; [mdi, iCtx] _ InverseMapCtx[ctx]; IF OpenIncludedTable[mdi] THEN { t _ [iBase.FirstCtxSe[iCtx]]; CloseIncludedTable[]} ELSE t _ nullSEToken; RETURN}; CtxNext: PUBLIC PROC [ctx: CTXIndex, t: SEToken] RETURNS [next: SEToken] = { mdi: MDIndex; iCtx: CTXIndex; [mdi, iCtx] _ InverseMapCtx[ctx]; IF t # nullSEToken AND OpenIncludedTable[mdi] THEN { next _ [iBase.NextSe[t]]; CloseIncludedTable[]} ELSE next _ nullSEToken; RETURN}; TokenHash: PUBLIC PROC [ctx: CTXIndex, t: SEToken] RETURNS [hti: HTIndex] = { mdi: MDIndex = InverseMapCtx[ctx].mdi; IF t # nullSEToken AND OpenIncludedTable[mdi] THEN { hti _ MapHti[iBase.seb[t].hash]; CloseIncludedTable[]} ELSE hti _ HTNull; RETURN}; TokenValue: PUBLIC PROC [ctx: CTXIndex, t: SEToken] RETURNS [v: WORD] = { mdi: MDIndex = InverseMapCtx[ctx].mdi; IF t # nullSEToken AND OpenIncludedTable[mdi] THEN { v _ iBase.seb[t].idValue; CloseIncludedTable[]} ELSE v _ 0; RETURN}; TokenSymbol: PUBLIC PROC [ctx: CTXIndex, t: SEToken] RETURNS [sei: ISEIndex] = { mdi: MDIndex = InverseMapCtx[ctx].mdi; SELECT TRUE FROM (mdi = OwnMdi) => sei _ t; OpenIncludedTable[mdi] => { sei _ LOOPHOLE[CopyIncludedSymbol[t, mdi]]; CloseIncludedTable[]}; ENDCASE => sei _ ISENull; RETURN}; -- copying across table boundaries SubString: TYPE = Strings.SubString; SubStringDescriptor: TYPE = Strings.SubStringDescriptor; SearchFileCtx: PUBLIC PROC [hti: HTIndex, ctx: IncludedCTXIndex] RETURNS [found: BOOL, sei: ISEIndex] = { desc: SubStringDescriptor; s: SubString = @desc; hash: [0..MemoCacheSize); iHti: HTIndex; iSei: ISEIndex; mdi: MDIndex = ctxb[ctx].module; SubStringForName[s, hti]; hash _ Inline.LongDivMod[ Inline.LongMult[LOOPHOLE[hti], LOOPHOLE[ctx]], MemoCacheSize].remainder; IF memoCache # NIL AND memoCache[hash].hti = hti AND memoCache[hash].ctx = ctx THEN RETURN [FALSE, ISENull]; IF OpenIncludedTable[mdi] THEN { iHti _ iBase.FindString[s]; IF iHti # HTNull AND (iHt[iHti].anyPublic OR iHt[iHti].anyInternal) THEN { iSei _ iBase.SearchContext[iHti, ctxb[ctx].map]; IF (found _ iSei # SENull) THEN sei _ CopyCtxSe[iSei, hti, ctx, mdi]} ELSE {found _ FALSE; sei _ ISENull}; CloseIncludedTable[]} ELSE {found _ FALSE; sei _ ISENull}; IF ~found AND memoCache # NIL THEN memoCache[hash] _ [hti:hti, ctx:ctx]; RETURN}; Delink: PUBLIC PROC [sei: ISEIndex] = { prev, next: ISEIndex; ctx: CTXIndex = seb[sei].idCtx; -- assumed not reset prev _ ctxb[ctx].seList; DO next _ NextSe[prev]; SELECT next FROM sei => EXIT; ctxb[ctx].seList, ISENull => ERROR; ENDCASE => prev _ next; ENDLOOP; IF NextSe[sei] = sei THEN ctxb[ctx].seList _ ISENull ELSE { IF sei = ctxb[ctx].seList THEN ctxb[ctx].seList _ prev; SetSeLink[prev, NextSe[sei]]}; SetSeLink[sei, ISENull]}; CopySymbol: PUBLIC PROC [mdi: MDIndex, iSei: SEIndex, depth: Closure] RETURNS [sei: SEIndex] = { SELECT TRUE FROM (mdi = OwnMdi) => sei _ iSei; OpenIncludedTable[mdi] => { sei _ CopyIncludedSymbol[iSei, mdi]; WITH s: seb[sei] SELECT FROM id => { CompleteType[s.idType, mdi, depth]; IF s.idType = typeTYPE THEN CompleteType[s.idInfo, mdi, depth]} ENDCASE => CompleteType[sei, mdi, depth]; CloseIncludedTable[]}; ENDCASE => sei _ SENull; RETURN}; -- context completion CompleteContext: PUBLIC PROC [ctx: IncludedCTXIndex, depth: Closure_unit] = { IF ctxb[ctx].copied < depth AND OpenIncludedTable[ctxb[ctx].module] THEN { FillContext[ctx, depth]; CloseIncludedTable[]}}; AugmentContext: PUBLIC PROC [ctx: IncludedCTXIndex, mdi: MDIndex] = { mdRoot: MDIndex; target: CTXIndex; [mdRoot, target] _ InverseMapCtx[ctx]; IF ~ctxb[ctx].reset AND OpenIncludedTable[mdi] THEN { newMdi: MDIndex = iBase.FindMdi[mdb[mdRoot].stamp]; IF newMdi # MDNull THEN FOR iCtx: IncludedCTXIndex _ iBase.mdb[newMdi].ctx, iBase.ctxb[iCtx].chain UNTIL iCtx = CTXNull DO IF iBase.ctxb[iCtx].map = target THEN { CopyCtxEntries[ctx, iCtx, mdi, unit]; IF ~iBase.ctxb[iCtx].complete THEN ctxb[ctx].complete _ FALSE; IF ctxb[ctx].complete THEN ResetCtx[ctx]; EXIT}; ENDLOOP; CloseIncludedTable[]}}; FillContext: PROC [ctx: IncludedCTXIndex, depth: Closure] = { mdi: MDIndex = ctxb[ctx].module; CopyCtxEntries[ctx, ctxb[ctx].map, mdi, depth]; ResetCtx[ctx]}; CopyContext: PROC [ctx, iCtx: CTXIndex, mdi: MDIndex, depth: Closure] = { WITH ctxb[ctx] SELECT FROM included => { tCtx: IncludedCTXIndex = LOOPHOLE[ctx]; IF ctxb[tCtx].copied < depth AND (~ctxb[tCtx].closed OR depth > unit) THEN { ctxb[tCtx].closed _ TRUE; CopyCtxEntries[tCtx, iCtx, mdi, depth]; ResetCtx[tCtx]}}; ENDCASE => NULL}; CopyCtxEntries: PROC [ctx: IncludedCTXIndex, iCtx: CTXIndex, mdi: MDIndex, depth: Closure] = { IF ctxb[ctx].copied < depth THEN { pSei: ISEIndex _ ISENull; ctxb[ctx].copied _ depth; FOR iSei: ISEIndex _ iBase.FirstCtxSe[iCtx], iBase.NextSe[iSei] UNTIL iSei = SENull DO hti: HTIndex = MapHti[iSeb[iSei].hash]; sei: ISEIndex _ IF hti = HTNull AND ctxb[ctx].reset THEN FirstCtxSe[ctx] ELSE SearchContext[hti, ctx]; IF ~ctxb[ctx].reset THEN { IF sei = SENull THEN sei _ CopyCtxSe[iSei, hti, ctx, mdi]; IF pSei # SENull AND NextSe[pSei] # sei THEN { Delink[sei]; SetSeLink[sei, NextSe[pSei]]; SetSeLink[pSei, sei]}; ctxb[ctx].seList _ pSei _ sei}; IF depth > unit AND sei # SENull THEN { subType: CSEIndex = UnderType[IF seb[sei].idType = typeTYPE THEN sei ELSE seb[sei].idType]; IF (depth = rc AND RCType[subType] # none) OR depth > rc THEN IF seb[sei].idType = typeTYPE THEN CompleteVariant[sei, mdi, depth] ELSE CompleteType[subType, mdi, depth]}; ENDLOOP; ctxb[ctx].complete _ TRUE}}; -- recursive type completion CompleteType: PROC [sei: SEIndex, mdi: MDIndex, depth: Closure] = { -- N.B. still incomplete if depth > rc type: CSEIndex = UnderType[sei]; WITH t: seb[type] SELECT FROM enumerated => IF depth > rc THEN CompleteEnumeration[type, mdi, depth]; record => CompleteRecord[type, mdi, TRUE, depth]; ref => IF depth > rc THEN CompleteType[t.refType, mdi, depth]; array => { CompleteType[t.indexType, mdi, depth]; CompleteType[t.componentType, mdi, depth]}; arraydesc => IF depth > rc THEN CompleteType[t.describedType, mdi, depth]; transfer, definition => NULL; -- *** temporary *** union => CompleteUnion[type, mdi, depth]; sequence => { CompleteType[seb[t.tagSei].idType, mdi, depth]; CompleteType[t.componentType, mdi, depth]}; relative => { CompleteType[t.baseType, mdi, depth]; CompleteType[t.offsetType, mdi, depth]}; subrange => CompleteType[t.rangeType, mdi, depth]; long, real => CompleteType[t.rangeType, mdi, depth]; ENDCASE => NULL}; CompleteEnumeration: PROC [sei: CSEIndex, mdi: MDIndex, depth: Closure] = { WITH type: seb[sei] SELECT FROM enumerated => { WITH c: ctxb[type.valueCtx] SELECT FROM included => IF c.copied < depth THEN { IF c.module = mdi THEN FillContext[LOOPHOLE[type.valueCtx], depth] ELSE { CloseIncludedTable[]; CompleteContext[LOOPHOLE[type.valueCtx], depth]; [] _ OpenIncludedTable[mdi]}}; ENDCASE => NULL}; ENDCASE => NULL}; CompleteRecord: PROC [sei: CSEIndex, mdi: MDIndex, doLink: BOOL, depth: Closure _ unit] = { WITH type: seb[sei] SELECT FROM record => { WITH type SELECT FROM linked => IF doLink THEN CompleteRecord[UnderType[linkType], mdi, TRUE, depth]; ENDCASE => NULL; WITH c: ctxb[type.fieldCtx] SELECT FROM included => IF c.copied < depth THEN { IF c.module = mdi THEN FillContext[LOOPHOLE[type.fieldCtx], depth] ELSE { CloseIncludedTable[]; CompleteContext[LOOPHOLE[type.fieldCtx], depth]; [] _ OpenIncludedTable[mdi]}}; ENDCASE => NULL}; ENDCASE => NULL}; CompleteUnion: PROC [sei: CSEIndex, mdi: MDIndex, depth: Closure] = { WITH type: seb[sei] SELECT FROM union => { CompleteType[seb[type.tagSei].idType, mdi, depth]; WITH c: ctxb[type.caseCtx] SELECT FROM included => IF c.copied < depth THEN { IF c.module = mdi THEN FillContext[LOOPHOLE[type.caseCtx], depth] ELSE { CloseIncludedTable[]; CompleteContext[LOOPHOLE[type.caseCtx], depth]; [] _ OpenIncludedTable[mdi]}}; ENDCASE => NULL}; ENDCASE => NULL}; CompleteVariant: PROC [sei: ISEIndex, mdi: MDIndex, depth: Closure] = { type: CSEIndex = UnderType[sei]; WITH seb[type] SELECT FROM record => CompleteRecord[type, mdi, FALSE, depth]; ENDCASE => NULL}; -- variant copying CopyUnion: PUBLIC PROC [ctx: CTXIndex, depth: Closure _ none] = { WITH c: ctxb[ctx] SELECT FROM included => IF ~c.reset AND OpenIncludedTable[c.module] THEN { FillUnionPart[LOOPHOLE[ctx], depth]; CloseIncludedTable[]}; ENDCASE}; FillUnionPart: PROC [ctx: IncludedCTXIndex, depth: Closure _ none] = { iRoot: ISEIndex = iCtxb[ctxb[ctx].map].seList; iSei: ISEIndex _ iRoot; DO IF iSei = SENull THEN EXIT; SELECT iBase.TypeForm[iSeb[iSei].idType] FROM union, sequence => { IF iSeb[iSei].hash # HTNull THEN [] _ CopyIncludedSymbol[iSei, ctxb[ctx].module] ELSE FillContext[LOOPHOLE[ctx], MAX[unit, depth]]; EXIT}; ENDCASE; IF (iSei _ iBase.NextSe[iSei]) = iRoot THEN EXIT; ENDLOOP}; FillUnion: PROC [sei: CSEIndex, mdi: MDIndex] = { WITH type: seb[sei] SELECT FROM record => { WITH c: ctxb[type.fieldCtx] SELECT FROM included => IF ~c.reset THEN { IF c.module = mdi THEN FillUnionPart[LOOPHOLE[type.fieldCtx]] ELSE { CloseIncludedTable[]; CopyUnion[type.fieldCtx]; [] _ OpenIncludedTable[mdi]}}; ENDCASE => NULL}; ENDCASE => NULL}; -- mappings MapHti: PROC [iHti: HTIndex] RETURNS [hti: HTIndex] = { desc: SubStringDescriptor; s: SubString = @desc; IF iHti = HTNull THEN hti _ HTNull ELSE { iBase.SubStringForName[s, iHti]; hti _ EnterString[s ! TableRelocated => {s.base _ iBase.ssb}]}; RETURN}; MissingHti: ERROR = CODE; InverseMapHti: PROC [hti: HTIndex] RETURNS [iHti: HTIndex] = { desc: SubStringDescriptor; s: SubString = @desc; IF hti = HTNull THEN iHti _ HTNull ELSE { SubStringForName[s, hti]; iHti _ iBase.FindString[s]; IF iHti = HTNull THEN ERROR MissingHti}; RETURN}; FindExternalCtx: PUBLIC PROC [mdi: MDIndex, iCtx: CTXIndex] RETURNS [ctx: IncludedCTXIndex] = { IF mdi # MDNull AND OpenIncludedTable[mdi] THEN { ctx _ MapCtx[mdi, iCtx]; CloseIncludedTable[]} ELSE ctx _ IncludedCTXNull; RETURN}; MapCtx: PROC [mdi: MDIndex, iCtx: CTXIndex] RETURNS [IncludedCTXIndex] = { ctx, last: IncludedCTXIndex; target: CTXIndex; mdRoot: MDIndex; IF iCtx = CTXNull THEN {mdRoot _ mdi; target _ CTXNull} ELSE { WITH iCtxb[iCtx] SELECT FROM included => [mdRoot, target] _ IncludedTargets[LOOPHOLE[iCtx]]; imported => { IF iBase.mdb[iCtxb[includeLink].module].defaultImport # iCtx THEN ERROR; -- need a signal to raise [mdRoot, target] _ IncludedTargets[includeLink]}; ENDCASE => {mdRoot _ mdi; target _ iCtx}}; last _ IncludedCTXNull; FOR ctx _ mdb[mdRoot].ctx, ctxb[ctx].chain UNTIL ctx = CTXNull DO IF ctxb[ctx].map = target AND target # CTXNull THEN RETURN [ctx]; last _ ctx; ENDLOOP; ctx _ table.Words[ctxType, CTXRecord.included.SIZE]; ctxb[ctx] _ CTXRecord[ rePainted: FALSE, varUpdated: FALSE, seList: ISENull, level: IF iCtx = CTXNull THEN lZ ELSE iCtxb[iCtx].level, extension: included[ chain: IncludedCTXNull, module: mdRoot, map: target, restricted: FALSE, complete: FALSE, closed: FALSE, reset: FALSE]]; IF last = IncludedCTXNull THEN mdb[mdRoot].ctx _ ctx ELSE ctxb[last].chain _ ctx; RETURN [ctx]}; InverseMapCtx: PROC [ctx: CTXIndex] RETURNS [mdi: MDIndex, iCtx: CTXIndex] = { WITH ctxb[ctx] SELECT FROM included => {mdi _ module; iCtx _ map}; imported => [mdi, iCtx] _ InverseMapCtx[includeLink]; ENDCASE => {mdi _ OwnMdi; iCtx _ ctx}; RETURN}; IncludedTargets: PROC [iCtx: IncludedCTXIndex] RETURNS [mdi: MDIndex, ctx: CTXIndex] = { oldMdi: MDIndex = iCtxb[iCtx].module; desc: SubStringDescriptor; s: SubString = @desc; iBase.SubStringForName[s, iBase.mdb[oldMdi].fileId]; mdi _ Copier.FindMdEntry[ id: MapHti[iBase.mdb[oldMdi].moduleId], version: iBase.mdb[oldMdi].stamp, file: MapHti[iBase.mdb[oldMdi].fileId]]; ctx _ iCtxb[iCtx].map; RETURN}; UnknownModule: PUBLIC SIGNAL [HTIndex] = CODE; FillModule: PUBLIC PROC [sei: ISEIndex, typeId: HTIndex, mdi: MDIndex] = { iHti: HTIndex; iSei: ISEIndex; IF mdi = MDNull OR ~OpenIncludedTable[mdi] THEN DummyCtxSe[sei] ELSE { -- allow failure exit BEGIN iHti _ InverseMapHti[typeId ! MissingHti => {GO TO failed}]; iSei _ iBase.SearchContext[iHti, iBase.stHandle.directoryCtx]; IF iSei = ISENull OR ~iSeb[iSei].public THEN GO TO failed; CopyCtxSeInfo[sei, iSei, mdi]; seb[sei].public _ FALSE; EXITS failed => {SIGNAL UnknownModule[seb[sei].hash]; DummyCtxSe[sei]}; END; CloseIncludedTable[]}}; DummyCtxSe: PROC [sei: ISEIndex] = { seb[sei].idType _ typeANY; seb[sei].idInfo _ seb[sei].idValue _ 0; seb[sei].extended _ seb[sei].public _ seb[sei].linkSpace _ FALSE; seb[sei].immutable _ seb[sei].constant _ TRUE; seb[sei].mark3 _ seb[sei].mark4 _ TRUE}; -- caching of (cons) types TypeCacheSize: CARDINAL = 83; -- prime < 256/3 TypeCacheIndex: TYPE = [0..TypeCacheSize); TypeCache: TYPE = ARRAY TypeCacheIndex OF RECORD [ mdi: MDIndex, iSei: SEIndex, -- the search keys sei: SEIndex]; -- the result typeCache: LONG POINTER TO TypeCache; TypeHash: PROC [mdi: MDIndex, iSei: SEIndex] RETURNS [TypeCacheIndex] = INLINE { RETURN [(LOOPHOLE[mdi,CARDINAL]*LOOPHOLE[iSei,CARDINAL]) MOD TypeCacheSize]}; CacheType: PROC [mdi: MDIndex, iSei, sei: SEIndex] = { IF typeCache # NIL THEN typeCache[TypeHash[mdi, iSei]] _ [mdi:mdi, iSei:iSei, sei:sei]}; -- copying symbols CopyIncludedSymbol: PROC [iSei: SEIndex, mdi: MDIndex] RETURNS [sei: SEIndex] = { IF iSei = SENull THEN RETURN [SENull]; WITH iSe: iSeb[iSei] SELECT FROM id => { hti: HTIndex = MapHti[iSe.hash]; IF iSe.idCtx IN StandardContext THEN { sei _ SearchContext[hti, iSe.idCtx]; IF sei = SENull THEN ERROR} ELSE { ctx: IncludedCTXIndex = MapCtx[mdi, iSe.idCtx]; tSei: ISEIndex = SearchContext[hti, ctx]; sei _ tSei; IF sei # SENull THEN seb[tSei].idCtx _ ctx ELSE { iMdi: MDIndex _ ctxb[ctx].module; IF iMdi = mdi OR ( iBase.stHandle.extended AND (~iSe.extended OR iBase.stHandle.definitionsFile) AND ~mdb[iMdi].shared) THEN sei _ CopyCtxSe[LOOPHOLE[iSei, ISEIndex], hti, ctx, mdi] ELSE { CloseIncludedTable[]; IF OpenIncludedTable[iMdi] THEN iSei _ iBase.SearchContext[InverseMapHti[hti], ctxb[ctx].map] ELSE [] _ OpenIncludedTable[iMdi_mdi]; sei _ CopyCtxSe[LOOPHOLE[iSei, ISEIndex], hti, ctx, iMdi]; CloseIncludedTable[]; [] _ OpenIncludedTable[mdi]}}}}; cons => WITH iType: iSe SELECT FROM mode => sei _ typeTYPE; basic => sei _ MapBasicType[iType.code]; ENDCASE => { i: TypeCacheIndex = TypeHash[mdi, iSei]; IF typeCache # NIL AND typeCache[i].iSei = iSei AND typeCache[i].mdi = mdi THEN sei _ typeCache[i].sei ELSE sei _ CopyNonCtxSe[LOOPHOLE[iSei, CSEIndex], mdi]}; ENDCASE; RETURN}; CopyCtxSe: PROC [iSei: ISEIndex, hti: HTIndex, ctx: CTXIndex, mdi: MDIndex] RETURNS [sei: ISEIndex] = { sei _ MakeCtxSe[hti, ctx]; CopyCtxSeInfo[sei, iSei, mdi]; RETURN}; CopyCtxSeInfo: PROC [sei, iSei: ISEIndex, mdi: MDIndex] = { OPEN id: seb[sei]; IF iSeb[iSei].idCtx = CTXNull THEN id.idCtx _ CTXNull; id.extended _ iSeb[iSei].extended; id.public _ iSeb[iSei].public; id.immutable _ iSeb[iSei].immutable; id.constant _ iSeb[iSei].constant; id.linkSpace _ iSeb[iSei].linkSpace; id.idType _ CopyIncludedSymbol[iSeb[iSei].idType, mdi]; IF iSeb[iSei].idType = typeTYPE THEN id.idInfo _ CopyIncludedSymbol[iSeb[iSei].idInfo, mdi] ELSE IF iSeb[iSei].constant AND (SELECT iBase.XferMode[iSeb[iSei].idType] FROM proc, program=> TRUE, ENDCASE=> FALSE) THEN id.idInfo _ CopyIncludedBody[iSeb[iSei].idInfo, sei, mdi] ELSE id.idInfo _ iSeb[iSei].idInfo; IF iSeb[iSei].idType = typeTYPE AND iCtxb[iSeb[iSei].idCtx].level # lZ AND ~iBase.stHandle.extended THEN id.idValue _ iSei - ISEIndex.FIRST ELSE id.idValue _ iSeb[iSei].idValue; id.mark3 _ id.mark4 _ TRUE; IF id.extended THEN CopyExtension[sei, iSei, mdi] ELSE IF id.linkSpace THEN id.idInfo _ 0}; currentBody: BTIndex; CopyExtension: PROC [sei, iSei: ISEIndex, mdi: MDIndex] = { iType: ExtensionType; iTree: Tree.Link; saveCurrentBody: BTIndex = currentBody; currentBody _ BTNull; [iType, iTree] _ iBase.FindExtension[iSei]; WITH iTree SELECT FROM subtree => IF iBase.tb[index].name = body THEN currentBody _ seb[sei].idInfo; ENDCASE; EnterExtension[sei, iType, InputExtension[iTree, mdi]]; currentBody _ saveCurrentBody}; InputExtension: PROC [t: Tree.Link, mdi: MDIndex] RETURNS [Tree.Link] = { InputTree: Tree.Map = { WITH link: t SELECT FROM hash => v _ [hash[index: MapHti[link.index]]]; symbol => v _ [symbol[index: LOOPHOLE[CopyIncludedSymbol[link.index, mdi]]]]; literal => v _ InputLiteral[link]; subtree => { iNode: Tree.Index = link.index; v _ SELECT iBase.tb[iNode].name FROM block, ditem => InputBlock[iNode], IN [forseq .. downthru] => InputBlock[iNode], openx => TreeOps.CopyTree[[baseP:@iBase.tb, link:iBase.tb[iNode].son[1]], InputTree], ENDCASE => TreeOps.CopyTree[[baseP:@iBase.tb, link:link], InputTree]; WITH v SELECT FROM subtree => { node: Tree.Index = index; SELECT tb[node].name FROM body => tb[node].info _ currentBody; block, ditem => ExitBlock[node]; safen => { -- needed for transition only (pass 4 now places safens) v _ tb[node].son[1]; tb[node].son[1] _ Tree.Null; TreeOps.FreeNode[node]}; IN [basicTC..discrimTC], cdot, IN [apply..typecode], exlist => { tb[node].info _ CopyIncludedSymbol[iBase.tb[iNode].info, mdi]; SELECT tb[node].name FROM construct, exlist => CompleteRecord[tb[node].info, mdi, TRUE]; dollar => UpdateDollar[node]; union => WITH tb[node].son[1] SELECT FROM symbol => CompleteRecord[UnderType[index], mdi, FALSE]; ENDCASE => ERROR; apply => FillUnion[UnderType[tb[node].info], mdi]; bindx => FillBinding[node, mdi]; ENDCASE}; IN [forseq..downthru] => NULL; do => { IF TreeOps.OpName[tb[node].son[1]] IN [forseq..downthru] THEN ExitBlock[TreeOps.GetNode[tb[node].son[1]]]; tb[node].info _ CARDINAL.LAST}; bind => FillBinding[node, mdi]; catch => { TreeOps.ScanList[tb[node].son[1], UpdateType]; tb[node].info _ CARDINAL.LAST}; IN [assign..join], decl, typedecl => tb[node].info _ CARDINAL.LAST; ENDCASE => NULL}; ENDCASE => NULL}; ENDCASE => ERROR; RETURN}; UpdateDollar: PROC [node: Tree.Index] = INLINE { WITH tb[node].son[1] SELECT FROM subtree => { sei: CSEIndex = tb[index].info; WITH type: seb[sei] SELECT FROM record => IF type.argument THEN WITH tb[node].son[2] SELECT FROM symbol => index _ SearchContext[seb[index].hash, type.fieldCtx]; ENDCASE => ERROR; ENDCASE}; ENDCASE}; UpdateType: Tree.Scan = { WITH t SELECT FROM subtree => tb[index].info _ CopyIncludedSymbol[tb[index].info, mdi]; ENDCASE}; FillBinding: PROC [node: Tree.Index, mdi: MDIndex] = { WITH tb[node].son[1] SELECT FROM subtree => { subNode: Tree.Index = index; rType: CSEIndex = WITH tb[subNode].son[2] SELECT FROM symbol => UnderType[seb[index].idType], subtree => tb[index].info, ENDCASE => ERROR; CompleteRecord[rType, mdi, FALSE]}; ENDCASE => ERROR}; InputLiteral: PROC [t: Tree.Link.literal] RETURNS [Tree.Link] = { WITH lit: t.index SELECT FROM word => lit.lti _ LiteralOps.CopyLiteral[[baseP:@iBase.ltb, index:lit]].lti; string => IF lit.sti # Literals.STNull THEN ERROR; -- temporary ENDCASE => ERROR; RETURN [t]}; InputBlock: PROC [iNode: Tree.Index] RETURNS [v: Tree.Link] = { OPEN TreeOps; iBti: BTIndex = iBase.tb[iNode].info; n: CARDINAL = iBase.tb[iNode].nSons; bti: BTIndex; IF iBti = BTNull THEN bti _ BTNull ELSE { ctx: IncludedCTXIndex = MapCtx[mdi, iBase.bb[iBti].localCtx]; bti _ table.Words[bodyType, BodyRecord.Other.SIZE]; bb[bti] _ BodyRecord[ link: , firstSon: BTNull, type: LOOPHOLE[CopyIncludedSymbol[iBase.bb[iBti].type, mdi]], localCtx: ctx, level: iBase.bb[iBti].level, sourceIndex: CARDINAL.LAST, info: , extension: Other[relOffset: ]]; LinkBti[bti: bti, parent: currentBody]; currentBody _ bti}; FOR i: CARDINAL IN [1 .. n] DO PushTree[InputTree[iBase.tb[iNode].son[i]]] ENDLOOP; PushNode[iBase.tb[iNode].name, n]; SetAttr[1, iBase.tb[iNode].attr1]; SetAttr[2, iBase.tb[iNode].attr2]; SetAttr[3, iBase.tb[iNode].attr3]; SetInfo[bti]; v _ PopTree[]; IF bti # BTNull THEN bb[bti].info _ [Internal[bodyTree: GetNode[v], thread: Tree.NullIndex, frameSize: ]]; RETURN}; ExitBlock: PROC [node: Tree.Index] = INLINE { IF tb[node].info # BTNull THEN currentBody _ ParentBti[tb[node].info]}; RETURN [InputTree[t]]}; CopyExternalBody: PUBLIC PROC [mdi: MDIndex, iBti: CBTIndex] RETURNS [bti: CBTIndex] = { IF iBti # CBTNull AND mdi # MDNull AND OpenIncludedTable[mdi] THEN { sei: ISEIndex; iSei: ISEIndex = iBase.bb[iBti].id; IF iSei # ISENull THEN { sei _ LOOPHOLE[CopyIncludedSymbol[iSei, mdi]]; bti _ seb[sei].idInfo} ELSE bti _ CopyIncludedBody[iBti, ISENull, mdi]; CloseIncludedTable[]} ELSE bti _ CBTNull; RETURN}; CopyIncludedBody: PROC [iBti: CBTIndex, sei: ISEIndex, mdi: MDIndex] RETURNS [bti: CBTIndex] = { iCtx: CTXIndex; IF iBti = BTNull THEN bti _ CBTNull ELSE { iCtx _ iBase.bb[iBti].localCtx; WITH body: iBase.bb[iBti] SELECT FROM Outer => { bti _ table.Words[bodyType, BodyRecord.Callable.Outer.SIZE]; bb[LOOPHOLE[bti, OCBTIndex]] _ body}; Inner => { bti _ table.Words[bodyType, BodyRecord.Callable.Inner.SIZE]; bb[LOOPHOLE[bti, ICBTIndex]] _ body}; ENDCASE => ERROR; bb[bti].link _ [parent, BTNull]; bb[bti].firstSon _ BTNull; bb[bti].id _ sei; IF iCtx = CTXNull THEN {bb[bti].localCtx _ CTXNull; bb[bti].type _ RecordSENull} ELSE { bb[bti].localCtx _ MapCtx[mdi, iCtx]; bb[bti].type _ LOOPHOLE[CopyIncludedSymbol[iBase.bb[iBti].type, mdi]]}; IF iBase.bb[iBti].inline THEN { bb[bti].ioType _ CopyBodyType[iBase.bb[iBti].ioType, mdi]; WITH body: bb[bti].info SELECT FROM Internal => body.thread _ body.bodyTree _ Tree.NullIndex; ENDCASE} ELSE bb[bti].ioType _ IF sei = ISENull OR seb[seb[sei].idType].seTag = id THEN CopyBodyType[iBase.bb[iBti].ioType, mdi] ELSE UnderType[seb[sei].idType]}; RETURN}; MapBasicType: PROC [code: CARDINAL] RETURNS [CSEIndex] = { FOR sei: ISEIndex _ FirstCtxSe[StandardContext.FIRST], NextSe[sei] UNTIL sei = ISENull DO IF seb[sei].idType = typeTYPE THEN { tSei: CSEIndex = UnderType[sei]; WITH t: seb[tSei] SELECT FROM basic => IF t.code = code THEN RETURN [tSei]; ENDCASE}; ENDLOOP; ERROR}; CopyNonCtxSe: PROC [iSei: CSEIndex, mdi: MDIndex] RETURNS [sei: CSEIndex] = { tSei1, tSei2: SEIndex; WITH iType: iSeb[iSei] SELECT FROM enumerated => { tCtx: CTXIndex; sei _ MakeNonCtxSe[SERecord.cons.enumerated.SIZE]; tCtx _ IF iType.valueCtx IN StandardContext THEN iType.valueCtx ELSE CopyIncludedValues[iType.unpainted, iType.valueCtx, mdi, sei]; seb[sei].typeInfo _ enumerated[ ordered: iType.ordered, machineDep: iType.machineDep, unpainted: iType.unpainted, sparse: iType.sparse, valueCtx: tCtx, empty: iType.empty, nValues: iType.nValues]; CacheType[mdi, iSei, sei]}; record => { tCtx: CTXIndex = IF iType.fieldCtx IN StandardContext THEN iType.fieldCtx ELSE MapCtx[mdi, iType.fieldCtx]; WITH iType SELECT FROM notLinked => { sei _ MakeNonCtxSe[SERecord.cons.record.notLinked.SIZE]; CacheType[mdi, iSei, sei]; seb[sei].typeInfo _ record[ machineDep: iType.machineDep, painted: iType.painted, argument: iType.argument, hints: iType.hints, fieldCtx: tCtx, length: iType.length, monitored: iType.monitored, linkPart: notLinked[]]}; linked => { sei _ MakeNonCtxSe[SERecord.cons.record.linked.SIZE]; CacheType[mdi, iSei, sei]; tSei1 _ CopyIncludedSymbol[linkType, mdi]; seb[sei].typeInfo _ record[ machineDep: iType.machineDep, painted: iType.painted, argument: iType.argument, hints: iType.hints, fieldCtx: tCtx, length: iType.length, monitored: iType.monitored, linkPart: linked[linkType: tSei1]]}; ENDCASE; IF ~iType.painted OR (iType.hints.refField AND iType.hints.unifield) THEN CopyContext[tCtx, iType.fieldCtx, mdi, unit]}; ref => { sei _ MakeNonCtxSe[SERecord.cons.ref.SIZE]; CacheType[mdi, iSei, sei]; tSei1 _ CopyIncludedSymbol[iType.refType, mdi]; seb[sei].typeInfo _ ref[ refType: tSei1, counted: iType.counted, var: iType.var, readOnly: iType.readOnly, ordered: iType.ordered, list: iType.list, basing: iType.basing]}; array => { sei _ MakeNonCtxSe[SERecord.cons.array.SIZE]; CacheType[mdi, iSei, sei]; tSei1 _ CopyIncludedSymbol[iType.indexType, mdi]; tSei2 _ CopyIncludedSymbol[iType.componentType, mdi]; seb[sei].typeInfo _ array[ packed: iType.packed, indexType: tSei1, componentType: tSei2]}; arraydesc => { sei _ MakeNonCtxSe[SERecord.cons.arraydesc.SIZE]; CacheType[mdi, iSei, sei]; tSei1 _ CopyIncludedSymbol[iType.describedType, mdi]; seb[sei].typeInfo _ arraydesc[ readOnly: iType.readOnly, var: iType.var, describedType: tSei1]}; transfer => { -- do not use cache (in case of importing) argSei1, argSei2: CSEIndex; sei _ MakeNonCtxSe[SERecord.cons.transfer.SIZE]; argSei1 _ CopyArgs[iType.typeIn, mdi, FALSE]; argSei2 _ CopyArgs[iType.typeOut, mdi, FALSE]; seb[sei].typeInfo _ transfer[ mode: iType.mode, safe: iType.safe, typeIn: argSei1, typeOut: argSei2]}; definition => { sei _ MakeNonCtxSe[SERecord.cons.definition.SIZE]; seb[sei].typeInfo _ definition[ nGfi: iType.nGfi, named: iType.named, defCtx: MapCtx[mdi, iType.defCtx]]}; union => { tag: ISEIndex; tCtx: CTXIndex; sei _ MakeNonCtxSe[SERecord.cons.union.SIZE]; CacheType[mdi, iSei, sei]; tCtx _ MapCtx[mdi, iType.caseCtx]; tag _ CopyCtxSe[iType.tagSei, MapHti[iSeb[iType.tagSei].hash], CTXNull, mdi]; seb[sei].typeInfo _ union[ caseCtx: tCtx, machineDep: iType.machineDep, overlaid: iType.overlaid, controlled: iType.controlled, tagSei: tag, hints: iType.hints]}; sequence => { tag: ISEIndex; sei _ MakeNonCtxSe[SERecord.cons.sequence.SIZE]; CacheType[mdi, iSei, sei]; tSei1 _ CopyIncludedSymbol[iType.componentType, mdi]; tag _ CopyCtxSe[iType.tagSei, MapHti[iSeb[iType.tagSei].hash], CTXNull, mdi]; seb[sei].typeInfo _ sequence[ packed: iType.packed, controlled: iType.controlled, machineDep: iType.machineDep, tagSei: tag, componentType: tSei1]}; relative => { tSei3: SEIndex; sei _ MakeNonCtxSe[SERecord.cons.relative.SIZE]; CacheType[mdi, iSei, sei]; tSei1 _ CopyIncludedSymbol[iType.baseType, mdi]; tSei2 _ CopyIncludedSymbol[iType.offsetType, mdi]; tSei3 _ IF iType.resultType = iType.offsetType THEN tSei2 ELSE CopyIncludedSymbol[iType.resultType, mdi]; seb[sei].typeInfo _ relative[ baseType: tSei1, offsetType: tSei2, resultType: tSei3]}; opaque => { sei _ MakeNonCtxSe[SERecord.cons.opaque.SIZE]; CacheType[mdi, iSei, sei]; tSei1 _ CopyIncludedSymbol[iType.id, mdi]; seb[sei].typeInfo _ opaque[ lengthKnown: iType.lengthKnown, length: iType.length, id: LOOPHOLE[tSei1]]}; zone => { sei _ MakeNonCtxSe[SERecord.cons.zone.SIZE]; seb[sei].typeInfo _ zone[mds: iType.mds, counted: iType.counted]; CacheType[mdi, iSei, sei]}; subrange => { sei _ MakeNonCtxSe[SERecord.cons.subrange.SIZE]; tSei1 _ CopyIncludedSymbol[iType.rangeType, mdi]; seb[sei].typeInfo _ subrange[ filled: iType.filled, empty: iType.empty, rangeType: tSei1, origin: iType.origin, range: iType.range]; CacheType[mdi, iSei, sei]}; long => { sei _ MakeNonCtxSe[SERecord.cons.long.SIZE]; CacheType[mdi, iSei, sei]; tSei1 _ CopyIncludedSymbol[iType.rangeType, mdi]; seb[sei].typeInfo _ long[rangeType: tSei1]}; real => { sei _ MakeNonCtxSe[SERecord.cons.real.SIZE]; CacheType[mdi, iSei, sei]; tSei1 _ CopyIncludedSymbol[iType.rangeType, mdi]; seb[sei].typeInfo _ real[rangeType: tSei1]}; any => { sei _ MakeNonCtxSe[SERecord.cons.any.SIZE]; seb[sei].typeInfo _ any[]; CacheType[mdi, iSei, sei]}; ENDCASE => ERROR; seb[sei].mark3 _ seb[sei].mark4 _ TRUE; RETURN}; CopyBodyType: PROC [iSei: CSEIndex, mdi: MDIndex] RETURNS [sei: CSEIndex] = { argSei1, argSei2: CSEIndex; WITH iType: iSeb[iSei] SELECT FROM transfer => { sei _ MakeNonCtxSe[SERecord.cons.transfer.SIZE]; argSei1 _ CopyArgs[iType.typeIn, mdi, TRUE]; argSei2 _ CopyArgs[iType.typeOut, mdi, TRUE]; seb[sei].typeInfo _ transfer[ mode: iType.mode, safe: iType.safe, typeIn: argSei1, typeOut: argSei2]}; ENDCASE => ERROR; seb[sei].mark3 _ seb[sei].mark4 _ TRUE; RETURN}; CopyArgs: PROC [iargSei: CSEIndex, mdi: MDIndex, mapped: BOOL] RETURNS [argSei: CSEIndex] = { IF iargSei = CSENull THEN argSei _ CSENull ELSE WITH t: iSeb[iargSei] SELECT FROM record => { iCtx: CTXIndex = t.fieldCtx; ctx: CTXIndex; argSei _ MakeNonCtxSe[SERecord.cons.record.notLinked.SIZE]; IF ~mapped THEN ctx _ NewCtx[iCtxb[iCtx].level] ELSE { tCtx: IncludedCTXIndex = MapCtx[mdi, iCtx]; ctxb[tCtx].complete _ TRUE; ResetCtx[tCtx]; ctx _ tCtx}; IF ctxb[ctx].seList = ISENull THEN { seChain: ISEIndex _ MakeSeChain[ctx, iBase.CtxEntries[iCtx], FALSE]; sei, iSei: ISEIndex; ctxb[ctx].seList _ seChain; FOR iSei _ iCtxb[iCtx].seList, iBase.NextSe[iSei] UNTIL iSei = ISENull DO sei _ seChain; seChain _ NextSe[seChain]; seb[sei].hash _ MapHti[iSeb[iSei].hash]; CopyCtxSeInfo[sei, iSei, mdi]; ENDLOOP}; seb[argSei] _ SERecord[ mark3: TRUE, mark4: TRUE, body: cons[ record[ machineDep: FALSE, painted: FALSE, argument: TRUE, hints: t.hints, fieldCtx: ctx, length: t.length, monitored: FALSE, linkPart: notLinked[]]]]; IF typeCache # NIL THEN { i: TypeCacheIndex = TypeHash[mdi, iargSei]; typeCache[i] _ [mdi:mdi, iSei:iargSei, sei:argSei]}}; ENDCASE => argSei _ CopyNonCtxSe[iargSei, mdi]; RETURN}; CopyIncludedValues: PROC [full: BOOL, iCtx: CTXIndex, mdi: MDIndex, type: SEIndex] RETURNS [ctx: IncludedCTXIndex] = { iSei, sei, seChain: ISEIndex; ctx _ MapCtx[mdi, iCtx]; iSei _ iCtxb[iCtx].seList; IF full OR (iSei # SENull AND iSeb[iSeb[iSei].idType].seTag # id) THEN { seChain _ MakeSeChain[ctx, iBase.CtxEntries[iCtx], FALSE]; ctxb[ctx].seList _ seChain; ctxb[ctx].closed _ ctxb[ctx].reset _ TRUE; UNTIL iSei = SENull DO sei _ seChain; seChain _ NextSe[seChain]; seb[sei].hash _ MapHti[iSeb[iSei].hash]; seb[sei].extended _ seb[sei].linkSpace _ FALSE; seb[sei].immutable _ seb[sei].constant _ TRUE; seb[sei].public _ iSeb[iSei].public; seb[sei].idType _ type; seb[sei].idInfo _ 0; seb[sei].idValue _ iSeb[iSei].idValue; seb[sei].mark3 _ seb[sei].mark4 _ TRUE; iSei _ iBase.NextSe[iSei]; ENDLOOP; ctxb[ctx].copied _ full; ctxb[ctx].complete _ TRUE}; RETURN}; -- included module accounting ResetCtx: PROC [ctx: IncludedCTXIndex] = { IF ~ctxb[ctx].reset THEN {ResetCtxList[ctx]; ctxb[ctx].closed _ ctxb[ctx].reset _ TRUE}}; ResetIncludeContexts: PROC = { mdi: MDIndex; limit: MDIndex = table.Top[mdType]; ctx: IncludedCTXIndex; FOR mdi _ MDIndex.FIRST, mdi + MDRecord.SIZE UNTIL mdi = limit DO FOR ctx _ mdb[mdi].ctx, ctxb[ctx].chain UNTIL ctx = CTXNull DO ctxb[ctx].copied _ none; -- clear bits (**** until bootstrap ****) ResetCtx[ctx] ENDLOOP; ENDLOOP; ResetCaches[]}; Outer: PUBLIC PROC [mdi: MDIndex, inner: PROC [SymbolTable.Base]] = { IF mdi # MDNull AND OpenIncludedTable[mdi] THEN { inner[iBase ! UNWIND => {CloseIncludedTable[]}]; CloseIncludedTable[]}}; TableRelocated: PUBLIC SIGNAL = CODE; OpenIncludedTable: PROC [mdi: MDIndex] RETURNS [success: BOOL] = { base: SymbolTable.Base = IF mdi = OwnMdi THEN ownSymbols ELSE Copier.GetSymbolTable[mdi]; IF success _ (base # NIL) THEN { iBase _ base; IF mdi # OwnMdi THEN iBase.notifier _ IRelocNotify; INotify[]}; RETURN}; IRelocNotify: PROC [base: SymbolTable.Base] = { IF base = iBase THEN {INotify[]; SIGNAL TableRelocated}}; CloseIncludedTable: PROC = { IF iBase # ownSymbols THEN { iBase.notifier _ iBase.NullNotifier; Copier.FreeSymbolTable[iBase]}; iBase _ NIL}; }.