-- RCMapBuilderImpl.mesa -- Last Modified By Satterthwaite On June 29, 1982 11:30 am -- Last Modified By Paul Rovner On June 30, 1982 5:32 pm DIRECTORY Inline USING[LongCOPY], Table USING[Base, Limit], Symbols USING[SERecord, CSEIndex, ArraySEIndex, RecordSEIndex, SEIndex, ISEIndex, ISENull, CTXRecord, CTXIndex, SENull, CTXNull, HTNull, BitAddress, MDIndex], SymbolTable USING[Base], Environment USING[bitsPerWord, wordsPerPage], RCMap, RCMapOps USING[]; -- EXPORTS only RCMapBuilderImpl: MONITOR -- protects the current RCMap Base IMPORTS Inline EXPORTS RCMapOps = BEGIN OPEN Environment, Symbols, RCMap; -- Types -- UnionSEIndex: TYPE = Table.Base RELATIVE POINTER [0..Table.Limit) TO union cons SERecord; SequenceSEIndex: TYPE = Table.Base RELATIVE POINTER [0..Table.Limit) TO sequence cons SERecord; Handle: TYPE = RECORD[base: Base, index: Index]; MapMapItem: TYPE = RECORD[old, new: Index]; MapMapObj: PUBLIC TYPE = RECORD[SEQUENCE length: CARDINAL OF MapMapItem]; MapMap: TYPE = LONG POINTER TO MapMapObj; -- Variables that define the current RCMap Base-- rcmb: Base ← NIL; rcmbPages: CARDINAL; rcmbLimit: CARDINAL; rcmbx: CARDINAL; -- number of words in the base zone: UNCOUNTED ZONE ← NIL; outer: PROC[stb: SymbolTable.Base, mdi: MDIndex, inner: PROC[base: SymbolTable.Base]] ← NIL; --Errors -- TooManyRCMaps: ERROR = CODE; NIY: ERROR[msg: STRING]; --PROCs Initialize: PUBLIC ENTRY PROC[ptr: Base, nPages: CARDINAL, expansionZone: UNCOUNTED ZONE ← NIL] = {rcmb ← ptr; rcmbx ← 0; rcmbPages ← nPages; rcmbLimit ← nPages*Environment.wordsPerPage; zone ← expansionZone; InitStandardRCMaps[! UNWIND => NULL]}; EstablishOuter: PUBLIC ENTRY PROC [outerProc: PROC [stb: SymbolTable.Base, mdi: Symbols.MDIndex, inner: PROC[base: SymbolTable.Base]]] = {outer ← outerProc}; InitStandardRCMaps: INTERNAL PROC = { IF rcmbLimit < 3 THEN ExpandRCMSpace[]; -- make standard entries rcmb[nullIndex] ← [null[]]; rcmb[refIndex] ← [ref[]]; rcmb[controlLinkIndex] ← [controlLink[]]; rcmbx ← 3}; Finalize: PUBLIC ENTRY PROC = {IF zone # NIL THEN zone.FREE[@rcmb]}; GetBase: PUBLIC ENTRY PROC RETURNS[base: Base, nWords: CARDINAL] = {RETURN[rcmb, rcmbx]}; Acquire: PUBLIC ENTRY PROC[stb: SymbolTable.Base, sei: SEIndex] RETURNS[rcmx: Index] = {ENABLE UNWIND => NULL; RETURN[DoAcquire[stb, stb.UnderType[sei]]]}; DoAcquire: INTERNAL PROC[stb: SymbolTable.Base, csei: CSEIndex] RETURNS[rcmx: Index] = {RETURN[WITH cse: stb.seb[csei] SELECT FROM record => MakeRCMapForRecord[stb, LOOPHOLE[csei, RecordSEIndex]], array => MakeRCMapForArray[stb, LOOPHOLE[csei, ArraySEIndex]], sequence => MakeRCMapForSequence[stb, LOOPHOLE[csei, SequenceSEIndex]], union => MakeRCMapForUnion[stb, LOOPHOLE[csei, UnionSEIndex]], zone => (IF cse.counted THEN refIndex ELSE nullIndex), long => (IF (WITH rse: stb.seb[stb.UnderType[cse.rangeType] ] SELECT FROM ref => rse.counted, ENDCASE => FALSE) THEN refIndex ELSE nullIndex), ENDCASE => nullIndex]}; Include: PUBLIC ENTRY PROC[rcmb: Base, nWords: CARDINAL, zone: UNCOUNTED ZONE ← NIL] RETURNS[mm: MapMap ← NIL] = { ENABLE UNWIND => NULL; count: INTERNAL PROC[Index] RETURNS[stop: BOOL ← FALSE] = {mmEntries ← mmEntries + 1}; include: INTERNAL PROC[index: Index] RETURNS[stop: BOOL ← FALSE] = {mmi: MapMapItem = [old: index, new: MapRCMIndex[[rcmb, index]]]; IF mm # NIL THEN mm[nextMMX] ← mmi; nextMMX ← nextMMX + 1}; mmEntries: CARDINAL ← 0; nextMMX: CARDINAL ← 0; IF zone # NIL THEN {[] ← DoEnumerate[rcmb, nWords, count]; mm ← zone.NEW[MapMapObj[mmEntries]]}; [] ← DoEnumerate[rcmb, nWords, include]}; FindMapMapEntry: PUBLIC PROC[mapMap: MapMap, oldIndex: Index] RETURNS[Index] = {FOR i: CARDINAL IN [0..mapMap.length) DO IF mapMap[i].old = oldIndex THEN RETURN[mapMap[i].new]; ENDLOOP; RETURN[invalidIndex]}; Enumerate: PUBLIC ENTRY PROC[base: RCMap.Base, nWords: CARDINAL, proc: PROC[Index] RETURNS[stop: BOOL]] RETURNS[stopped: BOOL] = {ENABLE UNWIND => NULL; RETURN[DoEnumerate[base, nWords, proc]]}; DoEnumerate: INTERNAL PROC[base: RCMap.Base, nWords: CARDINAL, proc: PROC[Index] RETURNS[stop: BOOL]] RETURNS[stopped: BOOL ← FALSE] = { FOR rcmx: Index ← FIRST[Index], rcmx + Size[[base, rcmx]] UNTIL LOOPHOLE[rcmx, CARDINAL] >= nWords DO IF Complete[[base, rcmx]] AND proc[rcmx] THEN RETURN[TRUE]; ENDLOOP}; -- FOR DEBUGGING NextRCMap: SIGNAL = CODE; ListRCMaps: ENTRY PROC = { p:PROC[index: Index] RETURNS[stop: BOOL] = {SIGNAL NextRCMap; RETURN[FALSE]}; [] ← DoEnumerate[rcmb, rcmbx, p]}; Complete: INTERNAL PROC[h: Handle] RETURNS[BOOL] = INLINE {RETURN[WITH rcmr: h.base[h.index] SELECT FROM null => TRUE, ref => TRUE, controlLink => TRUE, oneRef => TRUE, simple => TRUE, nonVariant => rcmr.complete, variant => rcmr.complete, array => TRUE, sequence => TRUE, ENDCASE => ERROR]}; -- first level utility PROCs for constructing RCMap Objects NewARCM: INTERNAL PROC RETURNS[ans: AIndex] = {ans ← LOOPHOLE[AllocRCMap[SIZE[array Object]]]; rcmb[ans] ← [array[]]}; NewNVRCM: INTERNAL PROC[nComponents: [0..componentMaxIndex]] RETURNS[ans: NVIndex] = {ans ← LOOPHOLE[AllocRCMap[SIZE[nonVariant Object] + nComponents * SIZE[RCField]]]; rcmb[ans] ← [nonVariant[nComponents: nComponents, components: NULL]]; FOR i: CARDINAL IN [0..nComponents) DO rcmb[ans].components[i] ← []; ENDLOOP}; -- LOOPHOLE NewVRCM: INTERNAL PROC[nVariants: [0..componentMaxIndex], fdTag: FieldDescriptor] RETURNS[ans: VIndex] = {ans ← LOOPHOLE[AllocRCMap[SIZE[variant Object] + nVariants * SIZE[Index]]]; rcmb[ans] ← [variant[fdTag: fdTag, nVariants: nVariants, variants: NULL]]; FOR i: CARDINAL IN [0..nVariants) DO rcmb[ans].variants[i] ← nullIndex; ENDLOOP}; NewSeqRCM: INTERNAL PROC RETURNS[ans: SeqIndex] = {ans ← LOOPHOLE[AllocRCMap[SIZE[sequence Object]]]; rcmb[ans] ← [sequence[]]}; PopRCMX: INTERNAL PROC[x: CARDINAL] = {rcmbx ← x}; InstallSimplifiedRCM: INTERNAL PROC[srcm: UNSPECIFIED] RETURNS[ans: Index] = { proc: INTERNAL PROC[index: Index] RETURNS[stop: BOOL] = {stop ← (rcmb[index].type = simple) AND (srcm = rcmb[LOOPHOLE[index, SimpIndex]]) OR (rcmb[index].type = oneRef) AND (srcm = rcmb[LOOPHOLE[index, OneRefIndex]]); IF stop THEN ans ← index}; IF LOOPHOLE[srcm, null Object].type = null THEN RETURN[nullIndex]; IF LOOPHOLE[srcm, ref Object].type = ref THEN RETURN[refIndex]; IF DoEnumerate[rcmb, rcmbx, proc].stopped THEN RETURN[ans]; ans ← AllocRCMap[SIZE[simple Object]]; rcmb[LOOPHOLE[ans, RefIndex]] ← srcm}; MakeRCMapForRecord: INTERNAL PROC[stb: SymbolTable.Base, rsei: RecordSEIndex] RETURNS[Index] = { IF NOT stb.seb[rsei].hints.refField THEN RETURN[nullIndex]; IF stb.seb[rsei].hints.variant THEN RETURN[MakeRCMapForVRecord[stb, rsei]] ELSE RETURN[MakeRCMapForNVRecord[stb, rsei]]}; MakeRCMapForArray: INTERNAL PROC[stb: SymbolTable.Base, asei: ArraySEIndex] RETURNS[Index] = { compSEI: CSEIndex = stb.UnderType[stb.seb[asei].componentType]; IF IsRC[stb, compSEI] THEN { oldrcmbx: CARDINAL = rcmbx; ercmx: Index ← DoAcquire[stb, compSEI]; arcmx: AIndex ← NewARCM[]; simpRCM: UNSPECIFIED; simplified: BOOL; IF stb.seb[asei].packed THEN ERROR NIY["packed RC arrays"L]; rcmb[arcmx] ← [array[wordsPerElement: stb.WordsForType[compSEI], nElements: stb.Cardinality[stb.seb[asei].indexType], rcmi: ercmx]]; [simpRCM, simplified] ← SimplifyRCM[arcmx]; IF simplified THEN {PopRCMX[oldrcmbx]; RETURN[InstallSimplifiedRCM[simpRCM]]} ELSE { x: Index; found: BOOL; [found, x] ← FindRCMap[[rcmb, arcmx], oldrcmbx]; IF found THEN {PopRCMX[oldrcmbx]; RETURN[x]} ELSE RETURN[arcmx]}; } ELSE RETURN[nullIndex]}; MakeRCMapForSequence: INTERNAL PROC[stb: SymbolTable.Base, seqsei: SequenceSEIndex] RETURNS[ans: Index] = { tagSEI: ISEIndex = stb.seb[seqsei].tagSei; componentSEI: SEIndex = stb.seb[seqsei].componentType; ercmi: Index; seqrcmx: SeqIndex; found: BOOL; oldrcmbx: CARDINAL = rcmbx; -- NOTE unlike for unions, there is no way to get back to the enclosing record type IF TRUE THEN ERROR NIY["Stand-alone Sequences"L]; IF NOT IsRC[stb, componentSEI] THEN RETURN[nullIndex]; IF NOT stb.seb[seqsei].controlled THEN ERROR NIY["computed sequences"L]; IF stb.seb[seqsei].packed THEN ERROR NIY["packed RC sequence elements"L]; ercmi ← DoAcquire[stb, stb.UnderType[componentSEI]]; seqrcmx ← NewSeqRCM[]; rcmb[seqrcmx].wordsPerElement ← stb.WordsForType[componentSEI]; rcmb[seqrcmx].fdLength ← [wordOffset: 0, bitFirst: stb.seb[tagSEI].idValue MOD bitsPerWord, bitCount: stb.seb[tagSEI].idInfo]; rcmb[seqrcmx].commonPart ← nullIndex; rcmb[seqrcmx].dataOffset ← (stb.seb[tagSEI].idValue + stb.seb[tagSEI].idInfo) / bitsPerWord; rcmb[seqrcmx].rcmi ← ercmi; [found, ans] ← FindRCMap[[rcmb, seqrcmx], oldrcmbx]; IF found THEN {PopRCMX[oldrcmbx]; RETURN[ans]} ELSE RETURN[seqrcmx]; }; MakeRCMapForUnion: INTERNAL PROC[stb: SymbolTable.Base, usei: UnionSEIndex] RETURNS[rcmx: Index ← invalidIndex] = { GetRCMX: INTERNAL PROC[stb: SymbolTable.Base, isei: ISEIndex] RETURNS[stop: BOOL] = -- get the rcmx for the enclosing record { rcsei: CSEIndex ← stb.UnderType[stb.TypeLink[isei]]; IF rcsei = SENull THEN ERROR; -- NOTE offset, inclusion of common parts rcmx ← MakeRCMapForRecord[stb, LOOPHOLE[rcsei, RecordSEIndex]]; RETURN[TRUE]}; -- stop the enumeration nVariants: CARDINAL ← stb.Cardinality[stb.seb[stb.seb[usei].tagSei].idType]; nFields: CARDINAL ← 0; IF NOT stb.seb[usei].hints.refField THEN RETURN[nullIndex]; FOR isei: ISEIndex ← stb.FirstCtxSe[stb.seb[usei].caseCtx], stb.NextSe[isei] UNTIL isei = ISENull DO nFields ← nFields + 1; ENDLOOP; [] ← EnumerateCtxIseis[stb, stb.seb[usei].caseCtx, GetRCMX, (nVariants = nFields)]; IF rcmx = invalidIndex THEN ERROR}; MakeRCMapForNVRecord: INTERNAL PROC[stb: SymbolTable.Base, rsei: RecordSEIndex] RETURNS[Index] = { n: CARDINAL = CountRCCommonComponents[stb, rsei]; oldrcmbx: CARDINAL = rcmbx; nvrcmx: NVIndex; simpRCM: UNSPECIFIED; simplified: BOOL; IF n = 0 THEN RETURN[nullIndex]; nvrcmx ← NewNVRCM[n]; IF StuffRCCommonComponents[stb, rsei, nvrcmx] # n THEN ERROR; [simpRCM, simplified] ← SimplifyRCM[nvrcmx]; IF simplified THEN {PopRCMX[oldrcmbx]; RETURN[InstallSimplifiedRCM[simpRCM]]} ELSE { x: Index; found: BOOL; rcmb[nvrcmx].complete ← TRUE; [found, x] ← FindRCMap[[rcmb, nvrcmx], oldrcmbx]; IF found THEN {PopRCMX[oldrcmbx]; RETURN[x]} ELSE RETURN[nvrcmx]}}; MakeRCMapForVRecord: INTERNAL PROC[stb: SymbolTable.Base, rsei: RecordSEIndex] RETURNS[ans: Index] = -- maybe a sequence-containing record { ncc: CARDINAL = CountRCCommonComponents[stb, rsei]; oldrcmbx: CARDINAL = rcmbx; nvrcmx: Index ← MakeRCMapForNVRecord[stb, rsei]; up: INTERNAL PROC[ucstb: SymbolTable.Base, ucser: union cons SERecord] = -- called once { nvc: CARDINAL = CountRCVariants[ucstb, ucser]; x: Index; found: BOOL; IF nvc + ncc = 0 THEN ERROR; IF nvc = 0 THEN ans ← nvrcmx ELSE { tagSEI: ISEIndex = ucser.tagSei; nVariants: CARDINAL ← ucstb.Cardinality[ucstb.seb[tagSEI].idType]; vrcmx: VIndex ← NewVRCM[nVariants: nVariants, fdTag: [wordOffset: ucstb.seb[tagSEI].idValue / bitsPerWord, bitFirst: ucstb.seb[tagSEI].idValue MOD bitsPerWord, bitCount: ucstb.seb[tagSEI].idInfo]]; FOR i: CARDINAL IN [0..nVariants) DO rcmb[vrcmx].variants[i] ← nvrcmx; ENDLOOP; -- NOTE LOOPHOLE IF StuffRCVariantComponents[ucstb, ucser, vrcmx, nVariants] # nvc THEN ERROR; rcmb[vrcmx].complete ← TRUE; [found, x] ← FindRCMap[[rcmb, vrcmx], oldrcmbx]; IF found THEN {PopRCMX[oldrcmbx]; ans ← x} ELSE ans ← vrcmx}}; sp: INTERNAL PROC[scstb: SymbolTable.Base, scser: sequence cons SERecord] = -- called once { IF NOT scser.controlled THEN ERROR NIY["computed sequences"L]; IF ncc = 0 AND NOT IsRC[scstb, scser.componentType] THEN ERROR; IF ~IsRC[scstb, scser.componentType] THEN ans ← nvrcmx ELSE { ercmi: Index = DoAcquire[scstb, scstb.UnderType[scser.componentType]]; tagSEI: ISEIndex ← scser.tagSei; seqrcmx: SeqIndex; found: BOOL; x: Index; IF scser.packed THEN ERROR NIY["packed RC sequence elements"L]; seqrcmx ← NewSeqRCM[]; rcmb[seqrcmx].wordsPerElement ← scstb.WordsForType[scser.componentType]; rcmb[seqrcmx].fdLength ← [wordOffset: scstb.seb[tagSEI].idValue / bitsPerWord, bitFirst: scstb.seb[tagSEI].idValue MOD bitsPerWord, bitCount: scstb.seb[tagSEI].idInfo]; rcmb[seqrcmx].commonPart ← nvrcmx; rcmb[seqrcmx].dataOffset ← (scstb.seb[tagSEI].idValue + scstb.seb[tagSEI].idInfo) / bitsPerWord; rcmb[seqrcmx].rcmi ← ercmi; [found, x] ← FindRCMap[[rcmb, seqrcmx], oldrcmbx]; IF found THEN {PopRCMX[oldrcmbx]; ans ← x} ELSE ans ← seqrcmx}}; IF NOT FindVariantField[stb, stb.seb[rsei].fieldCtx, up, sp] THEN ERROR}; -- second level utility PROCs for constructing RCMap Objects StuffRCCommonComponents: INTERNAL PROC -- if looking, will find old eqv ones [stb: SymbolTable.Base, rsei: RecordSEIndex, nvrcmx: NVIndex] RETURNS[nextIndex: CARDINAL]= { argrec: BOOL = stb.seb[rsei].argument; foffset: INTERNAL PROC[isei: ISEIndex] RETURNS[BitAddress] = {RETURN[IF argrec THEN stb.FnField[isei].offset ELSE stb.seb[isei].idValue]}; append: INTERNAL PROC[stb: SymbolTable.Base, isei: ISEIndex] RETURNS[stop: BOOL] = { sei: SEIndex ← stb.seb[isei].idType; IF (NOT (IsUnion[stb, sei] OR IsSequence[stb, sei])) AND (NOT stb.seb[isei].constant) AND IsRC[stb, sei] THEN { rcmb[nvrcmx].components[nextIndex] ← [ wordOffset: foffset[isei].wd, rcmi: DoAcquire[stb, stb.UnderType[sei]]]; nextIndex ← nextIndex + 1 }; RETURN[FALSE]; -- keep counting }; nextIndex ← 0; [] ← EnumerateRecordIseis[stb, rsei, append]; }; StuffRCVariantComponents: INTERNAL PROC [ stb: SymbolTable.Base, uc: union cons SERecord, vrcmx: VIndex, nVariants: CARDINAL] RETURNS[n: CARDINAL] = { srcvc: INTERNAL PROC[stb: SymbolTable.Base, isei: ISEIndex] RETURNS[stop: BOOL] = { IF IsRC[stb, isei, FALSE] THEN { rcmb[vrcmx].variants[stb.seb[isei].idValue] ← DoAcquire[stb, stb.UnderType[isei]]; n ← n + 1}; RETURN[FALSE]; -- keep counting }; nFields: CARDINAL ← 0; FOR isei: ISEIndex ← stb.FirstCtxSe[uc.caseCtx], stb.NextSe[isei] UNTIL isei = ISENull DO nFields ← nFields + 1; ENDLOOP; n ← 0; [] ← EnumerateCtxIseis[stb, uc.caseCtx, srcvc, (nVariants = nFields)]; }; SimplifyRCM: INTERNAL PROC[rcmx: Index] RETURNS[rcmr: UNSPECIFIED, simplified: BOOL] = { srcmr: simple Object ← [simple[]]; rrcmr: oneRef Object ← [oneRef[]]; nRefOffsets: CARDINAL ← 0; nSimpleVecEntries: CARDINAL ← 0; p: INTERNAL PROC[refOffset: CARDINAL] RETURNS[stop: BOOL] = { nRefOffsets ← nRefOffsets+1; IF ((nRefOffsets # 1) OR (refOffset > componentMaxIndex)) AND (refOffset > simpleMaxIndex) THEN RETURN[TRUE]; -- can't simplify. Fail. IF nRefOffsets = 1 AND refOffset <= componentMaxIndex THEN rrcmr.offset ← refOffset; IF refOffset <= simpleMaxIndex THEN {nSimpleVecEntries ← nSimpleVecEntries + 1; IF nSimpleVecEntries # nRefOffsets THEN RETURN[TRUE]; -- can't simplify. Fail. srcmr.refs[refOffset] ← TRUE; srcmr.length ← MAX[srcmr.length, refOffset + 1]}; RETURN[FALSE]; -- keep going }; simplified ← NOT EnumerateForSimplify[rcmx, p].stopped; IF simplified THEN {IF nRefOffsets = 0 THEN rcmr ← Object[null[]] ELSE IF nRefOffsets = 1 THEN {IF rrcmr.offset = 0 THEN rcmr ← Object[ref[]] ELSE rcmr ← rrcmr} ELSE rcmr ← srcmr} ELSE rcmr ← NIL}; EnumerateForSimplify: INTERNAL PROC[rcmx: Index, p: PROC[refOffset: CARDINAL] RETURNS[stop: BOOL], offset: CARDINAL ← 0] RETURNS[stopped: BOOL] = { MapArrayRCM: INTERNAL PROC[refOffset: CARDINAL, arcmx: AIndex] RETURNS[stop: BOOL] = { FOR i: CARDINAL IN [0..rcmb[arcmx].nElements) DO IF EnumerateForSimplify[rcmb[arcmx].rcmi, p, refOffset+i*rcmb[arcmx].wordsPerElement].stopped THEN RETURN[stop: TRUE]; ENDLOOP; RETURN[stop: FALSE]}; MapRecordRCM: INTERNAL PROC[refOffset: CARDINAL, nvrcmx: NVIndex] RETURNS[stop: BOOL] = { FOR i: CARDINAL IN [0..rcmb[nvrcmx].nComponents) DO IF EnumerateForSimplify[rcmb[nvrcmx].components[i].rcmi, p, refOffset+rcmb[nvrcmx].components[i].wordOffset].stopped THEN RETURN[stop: TRUE]; ENDLOOP; RETURN[stop: FALSE]}; -- EnumerateForSimplify begins here WITH rcmr: rcmb[rcmx] SELECT FROM nonVariant => stopped ← MapRecordRCM[offset, LOOPHOLE[rcmx]]; array => stopped ← MapArrayRCM[offset, LOOPHOLE[rcmx]]; null => stopped ← FALSE; ref => stopped ← p[offset]; controlLink => stopped ← p[offset]; oneRef => stopped ← p[offset+rcmr.offset]; simple => { FOR i: CARDINAL IN [0..rcmr.length) DO IF rcmr.refs[i] THEN IF p[offset+i].stop THEN RETURN[TRUE]; ENDLOOP; stopped ← FALSE}; variant, sequence => stopped ← TRUE; ENDCASE => ERROR}; --PROCS for poking around in the symbol table -- copied (GROAN) from RTWalkSymbolsImpl IsUnion: INTERNAL PROC [stb: SymbolTable.Base, seIndex: SEIndex] RETURNS[BOOL] = {RETURN[stb.seb[stb.UnderType[seIndex]].typeTag = union]}; -- copied (GROAN) from RTWalkSymbolsImpl IsSequence: INTERNAL PROC [stb: SymbolTable.Base, seIndex: SEIndex] RETURNS[BOOL] = {RETURN[stb.seb[stb.UnderType[seIndex]].typeTag = sequence]}; -- copied (GROAN) from RTWalkSymbolsImpl EnumerateRecordIseis: INTERNAL PROC [ stb: SymbolTable.Base, rsei: RecordSEIndex, p: PROC[stb: SymbolTable.Base, isei: ISEIndex] RETURNS[stop: BOOL], level: CARDINAL ← 0] RETURNS [stopped: BOOL] = { proc: INTERNAL PROC[stb: SymbolTable.Base, isei: ISEIndex] RETURNS[stop: BOOL] = { sei: SEIndex ← stb.seb[isei].idType; IF NOT (IsUnion[stb, sei] OR IsSequence[stb, sei]) OR level = 0 THEN RETURN[p[stb, isei]]; RETURN[FALSE]}; IF rsei = SENull THEN RETURN[FALSE]; WITH lrc: stb.seb[rsei] SELECT FROM linked => { stopped ← EnumerateRecordIseis[stb, LOOPHOLE[stb.UnderType[lrc.linkType]], p, level + 1]; IF stopped THEN RETURN[TRUE]}; ENDCASE; RETURN[EnumerateCtxIseis[stb, stb.seb[rsei].fieldCtx, proc]]}; -- copied (GROAN) from RTWalkSymbolsImpl EnumerateCtxIseis: INTERNAL PROC [ stb: SymbolTable.Base, ctx: CTXIndex, proc: PROC[stb: SymbolTable.Base, isei: ISEIndex] RETURNS[stop: BOOL], reallyComplete: BOOL ← FALSE] RETURNS[stopped: BOOL] = { isei: ISEIndex; IF ctx = CTXNull THEN RETURN[FALSE]; IF NOT reallyComplete THEN WITH c: stb.ctxb[ctx] SELECT FROM included => IF ~c.complete THEN { p: INTERNAL PROC[base: SymbolTable.Base] = -- called once { stopped ← EnumerateCtxIseis[base, c.map, proc]}; IF outer = NIL THEN ERROR ELSE outer[stb, c.module, p]; RETURN[stopped]; }; simple => NULL; ENDCASE => ERROR; FOR isei ← stb.FirstCtxSe[ctx], stb.NextSe[isei] UNTIL isei = ISENull DO IF stb.seb[isei].hash = HTNull AND stb.seb[isei].idCtx = CTXNull THEN LOOP; -- padding IF proc[stb, isei] THEN RETURN[TRUE]; ENDLOOP; RETURN[FALSE]}; FindVariantField: INTERNAL PROC [ stb: SymbolTable.Base, ctx: CTXIndex, unionProc: PROC[ucstb: SymbolTable.Base, ucser: union cons SERecord], sequenceProc: PROC[scstb: SymbolTable.Base, scser: sequence cons SERecord]] RETURNS[BOOL] = { p: INTERNAL PROC[stb: SymbolTable.Base, isei: ISEIndex] RETURNS[stop: BOOL] = { c: cons SERecord; sei: SEIndex ← stb.seb[isei].idType; c ← stb.seb[stb.UnderType[sei]]; WITH c: c SELECT FROM union => unionProc[stb, c]; sequence => sequenceProc[stb, c]; ENDCASE => RETURN[FALSE]; RETURN[TRUE]; }; RETURN[EnumerateCtxIseis[stb, ctx, p]]}; CountRCVariants: INTERNAL PROC [stb: SymbolTable.Base, uc: union cons SERecord] RETURNS [n: CARDINAL] = { count: INTERNAL PROC[stb: SymbolTable.Base, isei: ISEIndex] RETURNS[stop: BOOL] = { IF IsRC[stb, isei, FALSE] THEN n ← n+1; RETURN[FALSE]; -- keep counting }; tagCardinality: CARDINAL ← stb.Cardinality[stb.seb[uc.tagSei].idType]; n ← 0; [] ← EnumerateCtxIseis[stb, uc.caseCtx, count, (tagCardinality = stb.CtxEntries[uc.caseCtx])]}; CountRCCommonComponents: INTERNAL PROC [stb: SymbolTable.Base, rsei: RecordSEIndex] RETURNS [n: CARDINAL] = { count: INTERNAL PROC[stb: SymbolTable.Base, isei: ISEIndex] RETURNS[stop: BOOL] = { sei: SEIndex ← stb.seb[isei].idType; IF (NOT (IsUnion[stb, sei] OR IsSequence[stb, sei])) AND (NOT stb.seb[isei].constant) AND IsRC[stb, sei] THEN n ← n+1; -- don't count the variant part RETURN[FALSE]; -- keep counting }; n ← 0; [] ← EnumerateRecordIseis[stb, rsei, count]}; -- copied (GROAN) from RTWalkSymbolsImpl IsRC: INTERNAL PROC [stb: SymbolTable.Base, seIndex: SEIndex, checkCommon: BOOL ← TRUE] RETURNS[BOOL] = { cse: cons SERecord ← stb.seb[stb.UnderType[seIndex]]; WITH cr: cse SELECT FROM record => BEGIN rcP: INTERNAL PROC[stb: SymbolTable.Base, isei: ISEIndex] RETURNS[stop: BOOL] = BEGIN cse1: cons SERecord; sei: SEIndex ← stb.seb[isei].idType; cse1 ← stb.seb[stb.UnderType[sei]]; WITH cse1: cse1 SELECT FROM union => BEGIN urcP: INTERNAL PROC[stb: SymbolTable.Base, isei: ISEIndex] RETURNS[stop: BOOL] = BEGIN IF IsRC[stb, isei, FALSE] THEN RETURN[TRUE]; -- stop looking. This is it RETURN[FALSE]; -- keep looking END; tagCardinality: CARDINAL ← stb.Cardinality[stb.seb[cse1.tagSei].idType]; RETURN[EnumerateCtxIseis[stb, cse1.caseCtx, urcP, (tagCardinality = stb.CtxEntries[cse1.caseCtx])]]; END; sequence => IF IsRC[stb, cse1.componentType] THEN RETURN[TRUE]; -- stop looking. here tis ENDCASE => IF IsRC[stb, sei] THEN RETURN[TRUE]; -- stop looking. This is it RETURN[FALSE]; -- keep looking END; IF checkCommon THEN RETURN[cr.hints.refField] -- easy if the common parts are to be included ELSE IF NOT cr.hints.refField THEN RETURN[FALSE] -- neither the variants nor the common parts are RC ELSE RETURN[EnumerateCtxIseis[stb, cr.fieldCtx, rcP]]; -- look individually at the fields END; sequence, union => ERROR; transfer => RETURN[FALSE]; -- NOTE for now relative => RETURN[FALSE]; -- NOTE for now long => RETURN[WITH rse: stb.seb[stb.UnderType[cr.rangeType] ] SELECT FROM ref => rse.counted, ENDCASE => FALSE]; zone => RETURN[cr.counted]; array => RETURN[IsRC[stb, cr.componentType]]; ENDCASE => RETURN[FALSE]}; -- PROCs for managing RCMap Bases Size: INTERNAL PROC[h: Handle] RETURNS[CARDINAL] = { RETURN[WITH rcmh: h.base[h.index] SELECT FROM null => SIZE[null Object], --NOTE better be 1 ref => SIZE[ref Object], --NOTE better be 1 controlLink => SIZE[controlLink Object], --NOTE better be 1 oneRef => SIZE[oneRef Object], --NOTE better be 1 simple => SIZE[simple Object], --NOTE better be 1 nonVariant => SIZE[nonVariant Object] + rcmh.nComponents*SIZE[RCField], variant => SIZE[variant Object] + rcmh.nVariants*SIZE[Index], array => SIZE[array Object], sequence => SIZE[sequence Object], ENDCASE => ERROR]; }; EqualMaps: INTERNAL PROC [h1, h2: Handle] RETURNS [BOOL] = { WITH m1: h1.base[h1.index] SELECT FROM null, ref, controlLink => RETURN [h1.index = h2.index]; -- StandardRCMap's oneRef => RETURN [m1 = h2.base[h2.index]]; simple => RETURN [m1 = h2.base[h2.index]]; nonVariant => WITH m2: h2.base[h2.index] SELECT FROM nonVariant => { matched: BOOL ← (m1.complete AND m2.complete) AND (m1.nComponents = m2.nComponents); FOR i: NAT IN [0 .. m1.nComponents) WHILE matched DO matched ← (m1.components[i].wordOffset = m2.components[i].wordOffset) AND EqualMaps[[h1.base, m1.components[i].rcmi], [h2.base, m2.components[i].rcmi]]; ENDLOOP; RETURN [matched]}; ENDCASE => RETURN [FALSE]; variant => WITH m2: h2.base[h2.index] SELECT FROM variant => { matched: BOOL ← (m1.complete AND m2.complete) AND (m1.nVariants = m2.nVariants) AND (m1.fdTag = m2.fdTag); FOR i: NAT IN [0 .. m1.nVariants) WHILE matched DO matched ← EqualMaps[[h1.base, m1.variants[i]], [h2.base, m2.variants[i]]]; ENDLOOP; RETURN [matched]}; ENDCASE => RETURN [FALSE]; array => RETURN [WITH m2: h2.base[h2.index] SELECT FROM array => (m1.wordsPerElement = m2.wordsPerElement) AND (m1.nElements = m2.nElements) AND EqualMaps[[h1.base, m1.rcmi], [h2.base, m2.rcmi]], ENDCASE => FALSE]; sequence => RETURN [WITH m2: h2.base[h2.index] SELECT FROM sequence => (m1.wordsPerElement = m2.wordsPerElement) AND (m1.fdLength = m2.fdLength) AND EqualMaps[[h1.base, m1.commonPart], [h2.base, m2.commonPart]] AND (m1.dataOffset = m2.dataOffset) AND EqualMaps[[h1.base, m1.rcmi], [h2.base, m2.rcmi]], ENDCASE => FALSE]; ENDCASE => ERROR}; FindRCMap: INTERNAL PROC [h: Handle, nWords: CARDINAL ← LOOPHOLE[invalidIndex]] RETURNS [found: BOOL, index: Index] = { Test: INTERNAL PROC [x: Index] RETURNS [stop: BOOL ← FALSE] = {IF EqualMaps[h, [rcmb, x]] THEN {index ← x; stop ← TRUE}}; IF nWords = LOOPHOLE[invalidIndex, CARDINAL] THEN nWords ← rcmbx; WITH rcm: h.base[h.index] SELECT FROM null, ref, controlLink => {found ← TRUE; index ← h.index}; -- standard entries ENDCASE => found ← DoEnumerate[rcmb, nWords, Test]; RETURN}; EnterRCMap: INTERNAL PROC [h: Handle] RETURNS [new: Index] = { nw: CARDINAL = Size[h]; WITH m: h.base[h.index] SELECT FROM null, ref, controlLink, oneRef, simple => { new ← AllocRCMap[nw]; -- NOTE nw should be 1 Inline.LongCOPY[from: @h.base[h.index], to: @rcmb[new], nwords: nw]}; array => { cRcmi: Index = MapRCMIndex[[h.base, m.rcmi]]; new ← AllocRCMap[nw]; rcmb[new] ← [array[ wordsPerElement: m.wordsPerElement, nElements: m.nElements, rcmi: cRcmi]]}; nonVariant => { nvRcmi: RCMap.NVIndex ← LOOPHOLE[AllocRCMap[nw]]; rcmb[nvRcmi] ← [nonVariant[nComponents: m.nComponents, components: NULL, complete: FALSE]]; FOR i: NAT IN [0..m.nComponents) DO rcmb[nvRcmi].components[i] ← [m.components[i].wordOffset, MapRCMIndex[[h.base, m.components[i].rcmi]]]; ENDLOOP; rcmb[nvRcmi].complete ← TRUE; new ← nvRcmi}; variant => { vRcmi: RCMap.VIndex = LOOPHOLE[AllocRCMap[nw]]; rcmb[vRcmi] ← [variant[nVariants: m.nVariants, fdTag: m.fdTag, variants: NULL, complete: FALSE]]; FOR i: NAT IN [0..m.nVariants) DO rcmb[vRcmi].variants[i] ← MapRCMIndex[[h.base, m.variants[i]]]; ENDLOOP; rcmb[vRcmi].complete ← TRUE; new ← vRcmi}; sequence => { commonRcmi: Index = MapRCMIndex[[h.base, m.commonPart]]; cRcmi: Index = MapRCMIndex[[h.base, m.rcmi]]; new ← AllocRCMap[nw]; rcmb[new] ← [sequence[ wordsPerElement: m.wordsPerElement, fdLength: m.fdLength, commonPart: commonRcmi, dataOffset: m.dataOffset, rcmi: cRcmi]]}; ENDCASE => ERROR; RETURN}; MapRCMIndex: INTERNAL PROC [old: Handle] RETURNS [new: Index] = { found: BOOL; [found, new] ← FindRCMap[old]; IF ~found THEN new ← EnterRCMap[old]; RETURN}; AllocRCMap: INTERNAL PROC [nw: CARDINAL] RETURNS [Index] = { new: CARDINAL ← rcmbx; IF new = LOOPHOLE[invalidIndex, CARDINAL] THEN ERROR TooManyRCMaps; rcmbx ← rcmbx + nw; IF rcmbx > rcmbLimit THEN ExpandRCMSpace[]; RETURN[LOOPHOLE[new]]}; ExpandRCMSpace: INTERNAL PROC = { newLimit: CARDINAL = rcmbLimit + 4*Environment.wordsPerPage; newRCMB: RCMap.Base; T: TYPE = RECORD[SEQUENCE i: NAT OF WORD]; IF zone = NIL THEN ERROR TooManyRCMaps; newRCMB ← LOOPHOLE[zone.NEW[T[newLimit-SIZE[T[0]]]]]; IF rcmb # NIL THEN { Inline.LongCOPY[from: rcmb, to: newRCMB, nwords: rcmbLimit]; zone.FREE[@rcmb]}; rcmb ← newRCMB; rcmbLimit ← newLimit}; -- START HERE IF SIZE[null Object] # 1 OR SIZE[ref Object] # 1 OR SIZE[oneRef Object] # 1 OR SIZE[simple Object] # 1 OR SIZE[controlLink Object] # 1 THEN ERROR; END.