SymbolCopier.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Satterthwaite, May 8, 1986 4:41:55 pm PDT
Maxwell, August 11, 1983 8:34 am
Russ Atkinson (RRA) March 6, 1985 10:23:03 pm PST
DIRECTORY
Alloc: TYPE USING [Handle, Notifier, AddNotify, DropNotify, Top, Words],
Basics: TYPE USING [LongDivMod, LongMult],
ConvertUnsafe: TYPE USING [SubString],
Copier: TYPE USING [FindMdEntry, FreeSymbolTable, GetSymbolTable],
Literals: TYPE USING [LitIndex, STNull],
LiteralOps: TYPE USING [CopyLiteral],
OSMiscOps: TYPE USING [FreeWords, Words],
SourceMap: TYPE USING [nullLoc, Down],
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, Scan, MapFromX, Null, NullIndex, treeType],
TreeOps: TYPE USING [FreeNode, GetNode, OpName, PopTree, PushNode, PushTree, ScanList, SetAttr, SetInfo],
XSymbolSegment: TYPE SymbolSegment USING [ExtIndex, ExtRecord],
XTree: TYPE Tree USING [Index, Link, Null],
XTreeOps: TYPE USING [CopyTreeFromX];
SymbolCopier: PROGRAM
IMPORTS Alloc, Basics, Copier, LiteralOps, OSMiscOps, TreeOps, ownSymbols: SymbolPack, SourceMap, SymbolOps, XTreeOps
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 = ConvertUnsafe.SubString;
SearchFileCtx: PUBLIC PROC[hti: HTIndex, ctx: IncludedCTXIndex]
RETURNS[found: BOOL, sei: ISEIndex] = {
s: SubString;
hash: [0..MemoCacheSize);
iHti: HTIndex;
iSei: ISEIndex;
mdi: MDIndex = ctxb[ctx].module;
s ← SubStringForName[hti];
hash ← Basics.LongDivMod[
Basics.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] = {
s: SubString;
IF iHti = HTNull THEN hti ← HTNull
ELSE {
s ← iBase.SubStringForName[iHti];
hti ← EnterString[s ! TableRelocated => {s.base ← iBase.ssb}]};
RETURN};
MissingHti: ERROR = CODE;
InverseMapHti: PROC[hti: HTIndex] RETURNS[iHti: HTIndex] = {
s: SubString;
IF hti = HTNull THEN iHti ← HTNull
ELSE {
s ← SubStringForName[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[
levelOrigin: IF iCtx = CTXNull THEN 0 ELSE iCtxb[iCtx].levelOrigin,
levelOffset: IF iCtx = CTXNull THEN lZ ELSE iCtxb[iCtx].levelOffset,
seList: ISENull, varUpdated: FALSE,
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;
s: SubString;
s ← iBase.SubStringForName[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 iBase.CtxLevel[iSeb[iSei].idCtx] # 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;
FindXExtension: PROC[base: SymbolTable.Base, sei: ISEIndex]
RETURNS [type: ExtensionType, tree: XTree.Link] = {
OPEN Xs: XSymbolSegment;
extLimit: Xs.ExtIndex = LOOPHOLE[base.extLimit]; -- type may lie
FOR exti: Xs.ExtIndex ← Xs.ExtIndex.FIRST, exti + Xs.ExtRecord.SIZE UNTIL exti = extLimit DO
IF base.extb[exti].sei = sei THEN RETURN[base.extb[exti].type, base.extb[exti].tree];
ENDLOOP;
RETURN[$none, XTree.Null]};
CopyExtension: PROC[sei, iSei: ISEIndex, mdi: MDIndex] = {
iType: ExtensionType;
iTree: XTree.Link;
saveCurrentBody: BTIndex = currentBody;
currentBody ← BTNull;
[iType, iTree] ← FindXExtension[iBase, 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: XTree.Link, mdi: MDIndex] RETURNS[Tree.Link] = {
InputTree: Tree.MapFromX = {
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: XTree.Index = link.index;
v ← SELECT iBase.tb[iNode].name FROM
block, ditem => InputBlock[iNode],
IN [forseq .. downthru] => InputBlock[iNode],
openx =>
XTreeOps.CopyTreeFromX[[baseP:@iBase.tb, link:iBase.tb[iNode].son[1]], InputTree],
ENDCASE => XTreeOps.CopyTreeFromX[[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], textlit, exlist, shorten, IN [ord..val] => {
tb[node].info ← CopyIncludedSymbol[iBase.tb[iNode].info, mdi];
SELECT tb[node].name FROM
construct, exlist =>
CompleteRecord[UnderType[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 ← SourceMap.nullLoc};
bind => FillBinding[node, mdi];
catch => {
TreeOps.ScanList[tb[node].son[1], UpdateType];
tb[node].info ← SourceMap.nullLoc};
IN [assign..join], decl, typedecl => tb[node].info ← SourceMap.nullLoc;
ENDCASE => NULL};
ENDCASE => NULL};
ENDCASE => ERROR;
RETURN};
UpdateDollar: PROC [node: Tree.Index] = INLINE {
WITH tb[node].son[1] SELECT FROM
subtree => {
sei: CSEIndex = UnderType[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 => UnderType[tb[index].info],
ENDCASE => ERROR;
CompleteRecord[rType, mdi, FALSE]};
ENDCASE => ERROR};
InputLiteral: PROC [t: XTree.Link.literal] RETURNS [Tree.Link] = {
v: Literals.LitIndex;
WITH lit: t.index SELECT FROM
word => v ← LiteralOps.CopyLiteral[[baseP:@iBase.ltb, index:lit]];
string => {
IF lit.sti # Literals.STNull THEN ERROR; -- temporary
v ← [string[Literals.STNull]]};
ENDCASE => ERROR;
RETURN[[literal[v]]]};
InputBlock: PROC [iNode: XTree.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: SourceMap.nullLoc.Down[], 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[
nDummyGfi: iType.nDummyGfi,
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[iBase.CtxLevel[iCtx]]
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};
}.