-- RCMapBuilderImpl.mesa -- Last Modified By Satterthwaite On June 29, 1982 11:30 am -- Last Modified By Paul Rovner On January 12, 1983 11:34 am 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, NewRCMapOps USING[MapMapItem, MapMapObj, MapMap]; -- EXPORTS only RCMapBuilderImpl: MONITOR -- protects the current RCMap Base IMPORTS Inline EXPORTS NewRCMapOps = 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 = NewRCMapOps.MapMapItem; MapMapObj: TYPE = NewRCMapOps.MapMapObj; MapMap: TYPE = NewRCMapOps.MapMap; -- 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 { foffset: INTERNAL PROC[stb: SymbolTable.Base, isei: ISEIndex] RETURNS[BitAddress] = {RETURN[IF argrec THEN stb.FnField[isei].offset ELSE stb.seb[isei].idValue]}; rcmb[nvrcmx].components[nextIndex] _ [ wordOffset: foffset[stb, 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. ĘŽ˜JšēĪcœ<œ=œĪk œžœžœžœÜžœžœ@žœ"œžœ#œžœ žœžœžœ  œžœžœžœžœ'žœžœžœ=žœ"žœžœ)žœ&žœ"žœ1œžœ žœ žœ žœœž œžœžœ žœ-žœžœ œžœžœžœžœžœœĪn œžœžœžœ2žœ/ž œžœžœĄžœžœŸœžœžœžœKžœ†žœ7Ÿœžœžœ žœžœœ‡Ÿœžœžœžœžœžœžœžœ ŸœžœžœžœžœžœžœŸœžœžœžœ,žœžœžœžœžœ(Ÿ œžœžœ(žœžœžœžœžœ+žœ@žœEžœBžœ(žœ žœ žœžœžœ-žœžœPžœžœžœ žœžœŸœžœžœžœžœž œžœžœžœžœ žœžœžœžœžœžœžœžœ1žœžœžœžœžœWžœžœžœGžœžœ žœžœ žœ3žœJŸœžœžœ"žœžœžœžœžœžœžœžœžœžœŸ œžœžœžœ8žœ%žœžœžœ žœ žœžœžœžœžœ%Ÿ œžœžœ6žœ#žœžœžœ žœ žœžœžœžœ(žœžœžœ žœžœžœ žœžœžœžœœ žœžœŸ œžœžœžœžœžœžœ žœžœ+Ÿœžœžœ žœžœžœžœžœžœžœžœžœžœžœžœfžœžœ žœžœ<œŸœžœžœžœžœ žœ.Ÿœžœžœ&žœžœ žœ$žœ^žœžœžœžœžœžœ œŸœžœžœBžœžœ žœžœžœžœžœžœžœ$žœŸ œžœžœžœžœ žœ4ŸœžœžœžœŸœžœžœž œžœžœžœžœžœ-žœžœ#žœžœžœžœžœžœžœ žœžœžœžœžœžœžœ(žœžœžœžœŸœžœžœ5žœ žœžœžœžœžœžœžœ%žœžœ%Ÿœžœžœ,žœPžœžœžœhž œžœ žœžœžœžœžœ žœžœ(žœ"žœOžœžœžœžœžœžœžœŸœžœžœ7žœŧžœžœTœžœžœžœžœžœ#žœžœžœžœžœžœžœžœžœ žœžœžœžœÍžœÄžœžœžœžœžœŸœžœžœ4žœ"Ÿœžœžœ0žœžœ)œSžœžœžœ*œ.žœ(žœžœœžœFžœ žœžœžœžœžœOžœžœžœ\žœžœžœŸœžœžœ5žœžœ4žœ*ž œžœžœžœžœ)žœ0žœžœ5žœ žœžœ%žœžœ%žœJžœžœžœžœžœ Ÿœžœžœ5žœ&œ žœ5žœHžœžœ9œ žœAžœ žœžœžœ žœ žœžœCžœ˜žœcžœžœžœžœ#žœœ žœ@žœžœ$žœIžœžœžœžœžœ<œžœžœžœžœžœ žœ žœžœ"žœžœ žœ#žœžœ¯žœ#žœžœžœžœÍžœōžœžœžœžœžœ7žœžœ=Ÿœžœžœ&œQžœ žœžœ+žœžœžœžœžœžœžœ,žœžœ(žœžœ7žœžœžœ$žœžœ%žœžœžœžœ(žœžœžœžœžœ…žœžœœWŸœžœžœ{žœžœžœžœžœ(žœžœ žœžœžœ{žœžœœžœ žœPžœžœžœ^Ÿ œžœžœžœž œžœ`žœžœ žœžœ žœžœžœ/žœžœ+žœ&žœžœžœœžœžœ(žœ"žœ%žœ4žœ)žœžœžœœžœžœ'žœžœœžœ+žœžœžœžœ"žœžœžœžœ#žœ žœ žœžœžœŸœžœžœ&žœ žœžœžœ žœ žœ žœŸ œžœžœ žœžœžœ žœžœžœžœ žœkžœžœžœ žœ žœžœ Ÿ œžœžœ žœžœžœ žœžœžœžœ žœÃžœžœžœ žœ žœžœ $œžœžœžœ5žœ7žœ"žœ•žœžœžœžœžœžœžœžœžœžœžœžœ)žœžœžœ.œ)Ÿœžœžœ+žœžœžœ7)Ÿ œžœžœ+žœžœžœ:)Ÿœžœžœ`žœ(žœžœžœžœ žœ žœžœ(žœžœ=žœžœžœžœ žœžœžœžœžœžœžœžœžœžœžœDžœ;žœ žœžœžœ žœžœ<)ŸœžœžœCžœ(žœžœžœžœžœ žœžœžœžœžœžœžœžœžœžœžœ$žœ žœžœžœœ[žœ žœžœžœžœ*žœ.žœ žœžœžœ.žœžœžœžœžœžœ œžœžœžœžœžœžœžœŸœžœžœMžœ^žœ@žœžœ žœžœ(žœžœŒžœžœžœhžœžœžœžœžœžœ$Ÿœžœžœ;žœžœžœžœ(žœžœžœžœžœžœžœœ"žœŖŸœžœžœ7žœžœžœžœ(žœžœ?žœžœžœ&žœžœ'žœžœ  œ žœžœœP)Ÿœžœžœ8žœžœ žœžœ>žœ žœžœžœžœžœ(žœžœ žœ‡žœ žœžœ(žœžœžœ(žœžœžœžœžœžœžœžœœžœžœœžœ%žœDžœ›žœžœžœžœžœœ žœžœžœžœžœœ žœžœœžœ žœ žœžœ/œ žœžœžœ$žœžœžœ4œžœžœ-#œžœžœžœžœœžœžœœ žœžœ,žœžœEžœžœžœžœ#žœžœžœ"œŸœžœžœ žœžœžœžœžœžœžœœžœœžœœžœœžœœžœ'žœžœ"žœžœ#žœžœžœ Ÿ œžœžœžœžœ žœžœžœ!žœœžœ+žœ7žœžœžœ"žœžœžœ)žœžœžœžœ žœWžœnžœžœžœžœžœžœžœžœžœžœžœžœžœžœžœžœ žœZžœžœžœžœžœžœžœžœžœ<žœ&žœ7žœžœžœžœžœžœ?žœ$žœFžœ(žœ7žœžœ žœžœ Ÿ œžœžœžœžœžœ žœŸœžœžœ žœžœžœ žœžœžœ žœ žœžœžœžœžœžœ*žœœžœ1žœ Ÿ œžœžœ žœžœžœžœžœJœŋžœVžœ žœžœžœžœžœvžœžœCžœ\žœ žœžœžœžœžœGžœžœĶžœžœžœŸ œžœžœžœžœ)žœžœžœŸ œžœžœžœžœžœžœžœžœžœžœ,žœžœžœžœŸœžœžœžœHžœžœžœžœžœžœžœžœžœžœžœžœžœžœ žœžœ žœžœžœQžœ:œžœžœžœžœžœžœžœžœžœžœžœžœžœ˜ļö—…—{8Œė