-- Constructor.mesa, modified by Sweet, January 22, 1980 4:35 PM DIRECTORY AltoDefs: FROM "altodefs" USING [BYTE, charlength, wordlength], Code: FROM "code" USING [CodeNotImplemented, curctxlvl], CodeDefs: FROM "codedefs" USING [ BoVarIndex, ConsDestination, Lexeme, MaxParmsInStack, NullLex, VarComponent, VarIndex, VarNull], ComData: FROM "comdata" USING [tC0], ControlDefs: FROM "controldefs" USING [FieldDescriptor], FOpCodes: FROM "fopcodes" USING [ qBLT, qBLTL, qDSUB, qGADRB, qLADRB, qLI, qPUSH, qSUB, qWS, qWSD, qWSF], InlineDefs: FROM "inlinedefs" USING [BITSHIFT], LiteralOps: FROM "literalops" USING [MasterString], Literals: FROM "literals" USING [ltType, MSTIndex, stType], P5: FROM "p5" USING [ ConstructOnStack, Exp, GenTempLex, MoveToCodeWord, P5Error, SysCall, WriteCodeWord], P5L: FROM "p5l" USING [ AdjustComponent, ComponentForLex, CopyToTemp, CopyVarItem, EasilyLoadable, FieldOfComponent, GenAdd, GenVarItem, LoadComponent, LoadVar, MakeBo, ModComponent, OVarItem, ReleaseVarItem, ReusableCopies, TOSLex, VarForLex, VarVarAssign, Words], P5U: FROM "p5u" USING [ FieldAddress, MakeTreeLiteral, NextVar, OperandType, Out0, Out1, Out2, PushLitVal, WordAligned, WordsForOperand], SDDefs: FROM "sddefs" USING [sStringInit], Stack: FROM "stack" USING [Also, Dump, Forget, Mark, Pop, TempStore, Top], SymbolOps: FROM "symbolops" USING [ BitsForType, Cardinality, FnField, NextSe, RecordRoot, UnderType, WordsForType], Symbols: FROM "symbols" USING [ ArraySEIndex, BitAddress, bodyType, BTIndex, CBTIndex, ContextLevel, CSEIndex, CTXIndex, ctxType, HTIndex, ISEIndex, ISENull, lG, lZ, RecordSEIndex, SEIndex, seType, TypeClass], Table: FROM "table" USING [Base, Notifier], Tree: FROM "tree" USING [Index, Link, Map, Null, treeType], TreeOps: FROM "treeops" USING [FreeNode, ScanList, UpdateList]; Constructor: PROGRAM IMPORTS MPtr: ComData, CPtr: Code, InlineDefs, LiteralOps, P5, P5L, P5U, Stack, SymbolOps, TreeOps EXPORTS CodeDefs, P5 = BEGIN OPEN CodeDefs, SymbolOps; -- imported definitions BYTE: TYPE = AltoDefs.BYTE; wordlength: CARDINAL = AltoDefs.wordlength; charlength: CARDINAL = AltoDefs.charlength; BitAddress: TYPE = Symbols.BitAddress; BTIndex: TYPE = Symbols.BTIndex; CBTIndex: TYPE = Symbols.CBTIndex; ContextLevel: TYPE = Symbols.ContextLevel; CSEIndex: TYPE = Symbols.CSEIndex; CTXIndex: TYPE = Symbols.CTXIndex; HTIndex: TYPE = Symbols.HTIndex; ISEIndex: TYPE = Symbols.ISEIndex; ISENull: ISEIndex = Symbols.ISENull; lZ: ContextLevel = Symbols.lZ; lG: ContextLevel = Symbols.lG; RecordSEIndex: TYPE = Symbols.RecordSEIndex; SEIndex: TYPE = Symbols.SEIndex; TypeClass: TYPE = Symbols.TypeClass; tb: Table.Base; -- tree base (local copy) seb: Table.Base; -- semantic entry base (local copy) ctxb: Table.Base; -- context entry base (local copy) bb: Table.Base; -- body entry base (local copy) cb: Table.Base; -- code base (local copy) stb: Table.Base; -- string base (local copy) ltb: Table.Base; -- literal base (local copy) ConstructorNotify: PUBLIC Table.Notifier = BEGIN -- called by allocator whenever table area is repacked seb ← base[Symbols.seType]; ctxb ← base[Symbols.ctxType]; bb ← base[Symbols.bodyType]; stb ← base[Literals.stType]; tb ← base[Tree.treeType]; cb ← LOOPHOLE[tb]; ltb ← base[Literals.ltType]; RETURN END; -- state data and code for construction cd: PUBLIC ConsDestination; ConstructionError: SIGNAL = CODE; SetConsDest: PROCEDURE [r: VarIndex, exp: BOOLEAN ← FALSE] RETURNS [rVal: VarIndex] = BEGIN bor: BoVarIndex; base: VarComponent; rVal ← VarNull; WITH cb[r] SELECT FROM o => WITH vv: var SELECT FROM frame => BEGIN IF ~(vv.level = lG OR vv.level = CPtr.curctxlvl) THEN GO TO shouldBo; cd.bd ← vv.bd; cd.fOffset ← vv.wd; cd.fLevel ← vv.level; cd.inFrame ← TRUE; IF exp THEN rVal ← r ELSE P5L.ReleaseVarItem[r]; cd.wSize ← vv.wSize; cd.bSize ← vv.bSize; RETURN; EXITS shouldBo => NULL; END; frameup => NULL; linkup => NULL; ENDCASE => ERROR; bo, bdo, ind => NULL; ENDCASE => ERROR; bor ← P5L.MakeBo[r]; IF bor = VarNull THEN SIGNAL ConstructionError; -- should be caught above IF exp THEN BEGIN r1: VarIndex; [r1, rVal] ← P5L.ReusableCopies[bor, store]; bor ← P5L.MakeBo[r1]; END; BEGIN offset: VarComponent ← cb[bor].offset; WITH vv: offset SELECT FROM frame => BEGIN cd.bd ← vv.bd; cd.pDelta ← -INTEGER[vv.wd]; cd.wSize ← vv.wSize; cd.bSize ← vv.bSize; END; ENDCASE => ERROR; END; BEGIN base ← cb[bor].base; P5L.ReleaseVarItem[bor]; -- we're finished with it now WITH vv: base SELECT FROM frame => BEGIN IF vv.bSize # 0 OR ~(vv.level = lG OR vv.level = CPtr.curctxlvl) THEN GO TO loadIt; cd.pLevel ← vv.level; cd.pOffset ← vv.wd; cd.pLength ← vv.wSize; END; link => BEGIN cd.pLink ← TRUE; cd.pOffset ← vv.wd; END; ENDCASE => GO TO loadIt; EXITS loadIt => BEGIN wS: CARDINAL = P5L.Words[base.wSize, base.bSize]; P5L.LoadComponent[base]; cd.pSti ← Stack.Top[wS]; Stack.Also[n: wS, inLink: FALSE, tLevel: lZ, tOffset: 0]; --forget cd.pLoaded ← TRUE; cd.pLength ← wS; END; END; END; GetPointer: PROCEDURE [owd: CARDINAL] RETURNS [avar: VarComponent, newOwd: CARDINAL] = BEGIN -- invariant: cd.pLoaded => newOwd + cd.pDelta = owd SELECT TRUE FROM cd.pLoaded => avar ← [wSize: cd.pLength, space: stack[sti: cd.pSti]]; cd.inFrame => BEGIN avar ← [wSize: 1, space: faddr[wd: cd.fOffset+owd, level: cd.fLevel]]; cd.pLength ← 1; -- to be right if loaded cd.pDelta ← owd; -- to be right if loaded newOwd ← 0; RETURN END; cd.pLink => avar ← [wSize: 1, space: link[wd: cd.pOffset]]; cd.pLevel # lZ => avar ← [wSize: cd.pLength, space: frame[wd: cd.pOffset, level: cd.pLevel, immutable: TRUE]]; ENDCASE => ERROR; IF INTEGER[owd] >= cd.pDelta THEN newOwd ← CARDINAL[INTEGER[owd] - cd.pDelta] ELSE BEGIN P5L.LoadComponent[avar]; P5U.Out1[FOpCodes.qLI, CARDINAL[cd.pDelta] - owd]; IF cd.pLength # 1 THEN BEGIN P5U.Out1[FOpCodes.qLI, 0]; P5U.Out0[FOpCodes.qDSUB]; END ELSE P5U.Out0[FOpCodes.qSUB]; cd.pDelta ← owd; cd.pSti ← Stack.Top[cd.pLength]; newOwd ← 0; cd.pLink ← FALSE; cd.pLevel ← lZ; avar ← [wSize: cd.pLength, space: stack[sti: cd.pSti]]; cd.pLoaded ← TRUE; RETURN END; IF newOwd > LAST[BYTE] THEN BEGIN P5L.LoadComponent[avar]; P5L.GenAdd[newOwd, cd.pLength # 1]; cd.pDelta ← owd; cd.pSti ← Stack.Top[cd.pLength]; newOwd ← 0; cd.pLink ← FALSE; cd.pLevel ← lZ; avar ← [wSize: cd.pLength, space: stack[sti: cd.pSti]]; cd.pLoaded ← TRUE; END; END; LoadPointer: PROCEDURE [owd: CARDINAL] RETURNS [newOwd: CARDINAL] = BEGIN avar: VarComponent; [avar, newOwd] ← GetPointer[owd]; P5L.LoadComponent[avar]; cd.pSti ← Stack.Top[cd.pLength]; cd.pLoaded ← TRUE; END; ConsAssign: PROCEDURE [ atO: POINTER TO frame VarComponent, t: Tree.Link, l: Lexeme ← NullLex] = BEGIN dest: VarIndex; source: VarIndex; offset: frame VarComponent ← atO↑; useFrame: BOOLEAN ← cd.inFrame AND offset.wSize IN [1..2] AND offset.bSize = 0 AND (cd.fOffset+offset.wd) IN BYTE; useSwapped: BOOLEAN ← ~useFrame AND cd.pLength = 1 AND (offset.wSize = 0 OR (offset.bSize = 0 AND offset.wSize IN [1..2])); offset.bd ← offset.bd + cd.bd; IF useFrame AND cd.pLoaded THEN BEGIN Stack.Pop[]; cd.pLoaded ← FALSE END; IF ~useFrame THEN BEGIN IF ~useSwapped AND cd.pLoaded THEN BEGIN IF cd.pLink OR cd.pLevel # lZ THEN Stack.Pop[] ELSE BEGIN avar: VarComponent; avar ← Stack.TempStore[cd.pLength]; WITH avar SELECT FROM frame => BEGIN cd.pLevel ← level; cd.pOffset ← wd; END; link => BEGIN cd.pLink ← TRUE; cd.pOffset ← wd; END; ENDCASE => ERROR; END; cd.pLoaded ← FALSE; END; END; IF useSwapped THEN offset.wd ← LoadPointer[offset.wd]; source ← P5L.VarForLex[IF l # NullLex THEN l ELSE P5.Exp[t]]; IF useSwapped THEN BEGIN base: VarComponent; WITH cb[cd.pSti] SELECT FROM onStack => BEGIN WSOp: ARRAY [1..2] OF BYTE = [FOpCodes.qWS, FOpCodes.qWSD]; P5L.LoadVar[source]; IF offset.bSize = 0 THEN P5U.Out1[WSOp[offset.wSize], offset.wd] ELSE P5U.Out2[FOpCodes.qWSF, offset.wd, LOOPHOLE[ ControlDefs.FieldDescriptor[ offset: 0, posn: offset.bd, size: offset.bSize]]]; IF cd.remaining # 0 THEN BEGIN P5U.Out0[FOpCodes.qPUSH]; cd.pSti ← Stack.Top[]; Stack.Also[n: 1, inLink: cd.pLink, tOffset: cd.pOffset, tLevel: cd.pLevel]; END ELSE cd.pLoaded ← FALSE; RETURN END; inTemp => BEGIN cd.pLevel ← tLevel; cd.pOffset ← tOffset; base ← [wSize: 1, space: frame[wd: tOffset, level: tLevel, immutable: TRUE]]; END; inLink => BEGIN cd.pLink ← TRUE; cd.pOffset ← link; base ← [wSize: 1, space: link[wd: link]]; END; ENDCASE => ERROR; -- would have used swap but pointer got dumped when evaluating field Stack.Forget[cd.pSti]; cd.pLoaded ← FALSE; dest ← P5L.GenVarItem[bo]; cb[dest] ← [body: bo[base: base, offset: offset]]; END ELSE IF useFrame THEN BEGIN offset.wd ← offset.wd + cd.fOffset; offset.level ← cd.fLevel; dest ← P5L.OVarItem[offset]; END ELSE BEGIN base: VarComponent; [base, offset.wd] ← GetPointer[offset.wd]; IF cd.remaining # 0 THEN WITH base SELECT FROM stack => IF ~cd.inFrame THEN BEGIN -- this is our only copy, save it away base ← Stack.TempStore[cd.pLength]; WITH base SELECT FROM frame => BEGIN cd.pLevel ← level; cd.pOffset ← wd; END; link => BEGIN cd.pLink ← TRUE; cd.pOffset ← wd; END; ENDCASE => ERROR; cd.pLoaded ← FALSE; END; ENDCASE; dest ← P5L.GenVarItem[bo]; cb[dest] ← [body: bo[base: base, offset: offset]]; END; [] ← P5L.VarVarAssign[to: dest, from: source, isexp: FALSE]; cd.pLoaded ← FALSE; END; CountDups: Tree.Map = BEGIN node: Tree.Index; IF t = Tree.Null THEN GO TO normalRet; WITH t SELECT FROM subtree => BEGIN node ← index; SELECT tb[node].name FROM rowcons, construct => IF ~(tb[node].name = rowcons AND tb[node].attr1) THEN BEGIN tb[node].son[2] ← TreeOps.UpdateList[tb[node].son[2], CountDups]; GO TO normalRet END; all => BEGIN asei: Symbols.ArraySEIndex = tb[node].info; IF seb[asei].oldPacked AND SymbolOps.BitsForType[seb[asei].componentType] <= 8 THEN GO TO packed; tb[node].son[1] ← TreeOps.UpdateList[tb[node].son[1], CountDups]; GO TO normalRet EXITS packed => NULL; END; union => BEGIN IF tb[node].attr2 THEN cd.remaining ← cd.remaining+1; tb[node].son[2] ← TreeOps.UpdateList[tb[node].son[2], CountDups]; GO TO normalRet END; cast, pad => BEGIN tb[node].son[1] ← TreeOps.UpdateList[tb[node].son[1], CountDups]; GO TO normalRet END; safen => BEGIN IF cd.ignoreSafen THEN BEGIN v ← TreeOps.UpdateList[tb[node].son[1], CountDups]; tb[node].son[1] ← Tree.Null; TreeOps.FreeNode[node]; RETURN --[v] END ELSE BEGIN r: VarIndex = P5L.VarForLex[P5.Exp[tb[node].son[1]]]; sei: ISEIndex = P5L.CopyToTemp[r].sei; seb[sei].idType ← tb[node].info; TreeOps.FreeNode[node]; cd.remaining ← cd.remaining+1; RETURN [[symbol[sei]]]; END; END; ENDCASE; END; ENDCASE; cd.remaining ← cd.remaining+1; GO TO normalRet; EXITS normalRet => RETURN[t]; END; ConstructCountDown: PROCEDURE = BEGIN IF LOOPHOLE[(cd.remaining ← cd.remaining-1),INTEGER] < 0 THEN SIGNAL ConstructionError; RETURN END; -- RowCons: PUBLIC PROCEDURE [t: Tree.Link, node: Tree.Index] = BEGIN -- array initialization r: VarIndex; asei: CSEIndex = LOOPHOLE[tb[node].info]; saveCd: ConsDestination = cd; -- necessary in an inline offset: frame VarComponent; cd ← [ignoreSafen: t.tag = symbol]; -- + many defaults IF tb[node].attr1 THEN cd.remaining ← 1 ELSE tb[node].son[2] ← TreeOps.UpdateList[tb[node].son[2], CountDups]; r ← P5L.VarForLex[P5.Exp[t]]; [] ← SetConsDest[r, FALSE]; offset ← [wSize: cd.wSize, bSize: cd.bSize, space: frame[]]; Row[node, asei, @offset]; IF cd.remaining # 0 THEN SIGNAL ConstructionError; cd ← saveCd; RETURN END; RowConsExp: PUBLIC PROCEDURE [t: Tree.Link, node: Tree.Index] RETURNS [Lexeme] = BEGIN -- array (expression)initialization r, rr: VarIndex; asei: CSEIndex ← tb[node].info; awords: CARDINAL = WordsForType[asei]; saveCd: ConsDestination = cd; offset: frame VarComponent; cd ← [ignoreSafen: t = Tree.Null OR t.tag = symbol]; -- + many defaults tb[node].son[2] ← TreeOps.UpdateList[tb[node].son[2], CountDups]; r ← P5L.VarForLex[IF t = Tree.Null THEN P5.GenTempLex[awords] ELSE P5.Exp[t]]; rr ← SetConsDest[r, TRUE]; offset ← [wSize: cd.wSize, bSize: cd.bSize, space: frame[]]; Row[node, asei, @offset]; IF cd.remaining # 0 THEN SIGNAL ConstructionError; cd ← saveCd; RETURN[[bdo[rr]]] END; Row: PROCEDURE [node: Tree.Index, asei: CSEIndex, atO: POINTER TO READONLY frame VarComponent] = BEGIN -- handles ARRAY initialization n: CARDINAL; csei: CSEIndex; c: CARDINAL; filled: BOOLEAN ← FALSE; localstrconst, globalstrconst: BOOLEAN; tOffset: frame VarComponent = atO↑; offset: frame VarComponent ← atO↑; constrow: PROCEDURE [t: Tree.Link] = BEGIN -- outputs a row of constants scr: PROCEDURE [t: Tree.Link] = BEGIN msti: Literals.MSTIndex; WITH e:t SELECT FROM literal => WITH e.info SELECT FROM string => BEGIN msti ← LiteralOps.MasterString[index]; IF stb[msti].local THEN localstrconst ← TRUE ELSE globalstrconst ← TRUE; P5.WriteCodeWord[stb[msti].info]; END; ENDCASE => P5.P5Error[577]; ENDCASE => P5.P5Error[578]; n ← n+1; RETURN END; n ← 0; TreeOps.ScanList[t, scr]; RETURN END; -- of constrow scrow: PROCEDURE [t: Tree.Link] = BEGIN node: Tree.Index; offset.wSize ← eWSize; offset.bSize ← eBSize; IF t # Tree.Null THEN BEGIN DO -- until we get to something interesting WITH t SELECT FROM subtree => SELECT tb[index].name FROM pad => BEGIN eWords: CARDINAL; t ← tb[index].son[1]; -- note the variant may change here eWords ← P5U.WordsForOperand[t]; offset.wSize ← eWords; offset.bSize ← 0; END; cast => t ← tb[index].son[1]; ENDCASE => EXIT; ENDCASE => EXIT; ENDLOOP; WITH t SELECT FROM subtree => BEGIN node ← index; SELECT tb[node].name FROM rowcons => BEGIN Row[node, csei, @offset]; P5L.ModComponent[var: @offset, wd: eWSize, bd: eBSize]; RETURN END; construct => BEGIN MainConstruct[ tb[node].son[2], P5U.OperandType[t], P5U.FieldAddress, @offset]; P5L.ModComponent[var: @offset, wd: eWSize, bd: eBSize]; RETURN END; all => BEGIN -- convert this later AllConstruct[node, @offset]; P5L.ModComponent[var: @offset, wd: eWSize, bd: eBSize]; RETURN END; ENDCASE; END; ENDCASE; ConstructCountDown[]; ConsAssign[@offset, t]; END; -- of t # Tree.Null P5L.ModComponent[var: @offset, wd: eWSize, bd: eBSize]; RETURN END; -- of scrow totalBits: CARDINAL = tOffset.wSize * wordlength + tOffset.bSize; -- totalBits could overflow, but that would be a very large constructor fillBits: CARDINAL ← 0; eWSize: CARDINAL; eBSize: [0..wordlength); packed: BOOLEAN ← FALSE; IF tb[node].attr1 THEN BEGIN c ← P5.MoveToCodeWord[]; localstrconst ← globalstrconst ← FALSE; constrow[tb[node].son[2]]; ConstructCountDown[]; Stack.Dump[]; Stack.Mark[]; P5U.PushLitVal[c]; P5U.PushLitVal[n]; IF localstrconst AND globalstrconst THEN SIGNAL CPtr.CodeNotImplemented; P5U.Out1[IF localstrconst THEN FOpCodes.qLADRB ELSE FOpCodes.qGADRB,0]; [] ← LoadPointer[0]; IF cd.pLength # 1 THEN -- does a long pointer to array of short strings SIGNAL CPtr.CodeNotImplemented; -- make any sense? P5.SysCall[SDDefs.sStringInit]; RETURN END; WITH a: seb[asei] SELECT FROM array => BEGIN grain: [0..16); csei ← UnderType[a.componentType]; IF a.oldPacked THEN BEGIN SELECT SymbolOps.BitsForType[a.componentType] FROM 1 => grain ← 1; 2 => grain ← 2; 3,4 => grain ← 4; 5,6,7,8 => grain ← 8; ENDCASE => GO TO not; grain ← 8; -- *************** until after 6.0c bootstrap packed ← TRUE; -- change test when partial word packed arrays happen fillBits ← totalBits - Cardinality[UnderType[a.indexType]]*grain; IF fillBits # 0 THEN cd.remaining ← cd.remaining+1; eWSize ← 0; eBSize ← grain; EXITS not => packed ← FALSE; END ELSE packed ← FALSE; IF ~packed THEN BEGIN eBSize ← 0; eWSize ← SymbolOps.WordsForType[a.componentType]; END; END; ENDCASE => P5.P5Error[580]; TreeOps.ScanList[tb[node].son[2], scrow]; IF fillBits # 0 THEN BEGIN IF fillBits >= wordlength THEN SIGNAL ConstructionError; offset.wSize ← 0; offset.bSize ← fillBits; ConstructCountDown[]; ConsAssign[@offset, MPtr.tC0]; END; RETURN END; MainConstruct: PROCEDURE [ maint: Tree.Link, rsei: CSEIndex, fa: PROCEDURE[ISEIndex] RETURNS [BitAddress, CARDINAL], atO: POINTER TO READONLY frame VarComponent, fieldsei: ISEIndex ← ISENull] = BEGIN -- workhorse subroutine for construction in memory tOffset: frame VarComponent = atO↑; totalBits: CARDINAL = tOffset.wSize * wordlength + tOffset.bSize; more: BOOLEAN ← TRUE; rcsei: RecordSEIndex; ssmc: PROCEDURE [root: Tree.Link] = BEGIN offset: frame VarComponent; rep: BitAddress; res: CARDINAL; node: Tree.Index; iscontrolled: BOOLEAN ← FALSE; BEGIN -- to set up label "done" IF root # Tree.Null THEN BEGIN [rep, res] ← fa[fieldsei]; offset ← tOffset; P5L.FieldOfComponent[var: @offset, wd: rep.wd, bd: rep.bd, wSize: res / wordlength, bSize: res MOD wordlength]; IF fa # FnField AND totalBits <= wordlength THEN P5L.AdjustComponent[ var: @offset, rSei: rcsei, fSei: fieldsei, tBits: totalBits]; DO -- until we get to something interesting WITH root SELECT FROM subtree => SELECT tb[index].name FROM pad => BEGIN eWords: CARDINAL; root ← tb[index].son[1]; -- note the variant may change here eWords ← P5U.WordsForOperand[root]; offset.wSize ← eWords; offset.bSize ← 0; END; cast => root ← tb[index].son[1]; ENDCASE => EXIT; ENDCASE => EXIT; ENDLOOP; WITH root SELECT FROM subtree => BEGIN node ← index; SELECT tb[node].name FROM construct => BEGIN MainConstruct[tb[node].son[2], P5U.OperandType[root], P5U.FieldAddress, @offset]; GOTO done END; union => BEGIN UnionConstruct[node, rcsei, atO]; GO TO done END; rowcons => BEGIN Row[node, UnderType[seb[fieldsei].idType], @offset]; GO TO done END; all => BEGIN AllConstruct[node, @offset]; GO TO done; END; ENDCASE; END; ENDCASE; ConstructCountDown[]; ConsAssign[@offset, root]; END; -- IF root # Tree.Null EXITS done => NULL; END; fieldsei ← P5U.NextVar[NextSe[fieldsei]]; RETURN END; -- of ssmc IF fieldsei = ISENull THEN WITH seb[rsei] SELECT FROM record => BEGIN rcsei ← RecordRoot[LOOPHOLE[rsei]]; fieldsei ← P5U.NextVar[ctxb[seb[rcsei].fieldCtx].seList]; END; ENDCASE => P5.P5Error[589] ELSE rcsei ← LOOPHOLE[rsei]; TreeOps.ScanList[maint, ssmc]; RETURN END; -- of MainConstruct UnionConstruct: PROCEDURE [ node: Tree.Index, rootSei: RecordSEIndex, atO: POINTER TO READONLY frame VarComponent] = BEGIN -- construct a union part, atO↑ is offset of beginning of record tOffset: frame VarComponent = atO↑; offset: frame VarComponent ← tOffset; fieldsei: ISEIndex; constctx: CTXIndex; usei: CSEIndex = tb[node].info; rcsei: RecordSEIndex; tsei: ISEIndex; iscontrolled: BOOLEAN; tagvalue: CARDINAL; tBits: CARDINAL = tOffset.wSize * wordlength + tOffset.bSize; WITH seb[usei] SELECT FROM union => BEGIN iscontrolled ← controlled; IF iscontrolled THEN BEGIN tagAddr: BitAddress ← seb[tagSei].idValue; tagSize: [0..wordlength] ← seb[tagSei].idInfo; P5L.FieldOfComponent[ var: @offset, wd: tagAddr.wd, bd: tagAddr.bd, wSize: tagSize / wordlength, bSize: tagSize MOD wordlength]; IF tBits <= wordlength THEN P5L.AdjustComponent[ var: @offset, rSei: rootSei, fSei: tagSei, tBits: tBits]; END; END; ENDCASE => ERROR; WITH tb[node].son[1] SELECT FROM symbol => tsei ← index; ENDCASE => P5.P5Error[583]; tagvalue ← seb[tsei].idValue; rcsei ← LOOPHOLE[UnderType[tsei], RecordSEIndex]; constctx ← seb[rcsei].fieldCtx; fieldsei ← P5U.NextVar[ctxb[constctx].seList]; IF iscontrolled THEN BEGIN IF fieldsei # ISENull AND seb[fieldsei].idCtx # constctx THEN BEGIN -- a dummy fill field fillSize: [0..wordlength) ← seb[fieldsei].idInfo; b: CARDINAL ← offset.bSize+fillSize; tagvalue ← InlineDefs.BITSHIFT[tagvalue, fillSize]; offset.bSize ← b MOD wordlength; offset.wSize ← b / wordlength; fieldsei ← P5U.NextVar[NextSe[fieldsei]]; END; ConstructCountDown[]; ConsAssign[@offset, P5U.MakeTreeLiteral[tagvalue]]; END ELSE IF fieldsei # ISENull AND seb[fieldsei].idCtx # constctx THEN BEGIN -- no tag, but a fill field anyway fillSize: [0..wordlength) ← seb[fieldsei].idInfo; fillAddr: BitAddress ← seb[fieldsei].idValue; -- can't be full word P5L.FieldOfComponent[ var: @offset, wd: fillAddr.wd, bd: fillAddr.bd, bSize: fillSize]; IF tBits <= wordlength THEN P5L.AdjustComponent[ var: @offset, rSei: rootSei, fSei: fieldsei, tBits: tBits]; ConsAssign[@offset, MPtr.tC0]; fieldsei ← P5U.NextVar[NextSe[fieldsei]]; END; IF fieldsei # ISENull THEN MainConstruct[ tb[node].son[2], rootSei, P5U.FieldAddress, atO, fieldsei]; RETURN END; AllConstruct: PROCEDURE [ node: Tree.Index, atO: POINTER TO READONLY frame VarComponent] = BEGIN asei: CSEIndex = tb[node].info; csei: CSEIndex; -- element type t1: Tree.Link ← tb[node].son[1]; tOffset: frame VarComponent = atO↑; offset: frame VarComponent ← tOffset; totalBits: CARDINAL = tOffset.wSize * wordlength + tOffset.bSize; -- totalBits could overflow, should probably use LONG CARD fillBits: CARDINAL ← 0; eCount, owd: CARDINAL; eWSize: CARDINAL; eBSize: [0..wordlength); packed: BOOLEAN ← FALSE; grain: [0..16); bWords, e2Offset: CARDINAL; WITH a: seb[asei] SELECT FROM array => BEGIN csei ← UnderType[a.componentType]; IF a.oldPacked THEN BEGIN SELECT SymbolOps.BitsForType[a.componentType] FROM 1 => grain ← 1; 2 => grain ← 2; 3,4 => grain ← 4; 5,6,7,8 => grain ← 8; ENDCASE => GO TO not; packed ← TRUE; grain ← 8; -- *************** until after 6.0c bootstrap -- rethink fillBits when partial word packed arrays happen eCount ← Cardinality[UnderType[a.indexType]]; fillBits ← totalBits - eCount*grain; IF fillBits # 0 THEN cd.remaining ← cd.remaining+1; eWSize ← 0; eBSize ← grain; EXITS not => packed ← FALSE; END ELSE packed ← FALSE; IF ~packed THEN BEGIN eBSize ← 0; eWSize ← SymbolOps.WordsForType[a.componentType]; END; END; ENDCASE => ERROR; P5L.FieldOfComponent[var: @offset, wSize: eWSize, bSize: eBSize]; DO -- until we get to something interesting WITH t1 SELECT FROM subtree => BEGIN node1: Tree.Index = index; SELECT tb[node1].name FROM pad => BEGIN eWords: CARDINAL; t1 ← tb[node1].son[1]; -- note the variant may change here eWords ← P5U.WordsForOperand[t1]; offset.wSize ← eWords; offset.bSize ← 0; END; cast => t1 ← tb[node1].son[1]; ENDCASE => EXIT; END; ENDCASE => EXIT; ENDLOOP; IF ~packed THEN BEGIN IF tOffset.wSize > eWSize THEN cd.remaining ← cd.remaining + 1; -- so only pointer isn't lost BEGIN -- to set up label "done" WITH t1 SELECT FROM subtree => BEGIN node1: Tree.Index = index; SELECT tb[node1].name FROM construct => BEGIN MainConstruct[tb[node1].son[2], P5U.OperandType[t1], P5U.FieldAddress, @offset]; GO TO done END; rowcons => BEGIN Row[node, csei, @offset]; GO TO done END; all => BEGIN AllConstruct[node, @offset]; GO TO done END; ENDCASE; END; ENDCASE; ConstructCountDown[]; ConsAssign[@offset, tb[node].son[1]]; -- set first element EXITS done => NULL; END; e2Offset ← eWSize; END ELSE -- packed case BEGIN -- for bootstraping purposes, deal only with word aligned ePerWord: CARDINAL = wordlength/grain; val: VarComponent ← P5L.ComponentForLex[P5.Exp[t1]]; val ← P5L.EasilyLoadable[val, load]; -- could only clober with self THROUGH [0..MIN[ePerWord, eCount]) DO ConsAssign[@offset, Tree.Null, [bdo[P5L.OVarItem[val]]]]; P5L.ModComponent[var: @offset, bd: eBSize]; ENDLOOP; e2Offset ← 1; END; bWords ← tOffset.wSize - e2Offset; -- assumes tOffset.wSize >= 1 IF bWords = 0 THEN RETURN; owd ← LoadPointer[tOffset.wd]; -- load address of first element IF ~(cd.inFrame OR cd.pLink OR cd.pLevel # lZ) THEN BEGIN -- we need to load at least twice, save in temp tvar: VarComponent ← Stack.TempStore[cd.pLength]; P5L.LoadComponent[tvar]; -- load it back WITH vv: tvar SELECT FROM frame => BEGIN cd.pLevel ← vv.level; cd.pOffset ← vv.wd; END; ENDCASE => ERROR; END; cd.pLoaded ← FALSE; -- cd.pSti was maybe invalid anyway IF owd # 0 THEN P5L.GenAdd[owd, cd.pLength # 1]; ConstructCountDown[]; IF cd.pLength = 1 THEN -- otherwise stack gets too full P5U.Out1[FOpCodes.qLI, bWords]; owd ← LoadPointer[tOffset.wd + e2Offset]; -- load address of second IF (cd.remaining # 0 AND ~(cd.inFrame OR cd.pLink OR cd.pLevel # lZ)) THEN BEGIN -- still needed, save in temp tvar: VarComponent ← Stack.TempStore[cd.pLength]; P5L.LoadComponent[tvar]; -- load it back WITH vv: tvar SELECT FROM frame => BEGIN cd.pLevel ← vv.level; cd.pOffset ← vv.wd; END; ENDCASE => ERROR; END; cd.pLoaded ← FALSE; -- cd.pSti was maybe invalid anyway IF owd # 0 THEN P5L.GenAdd[owd, cd.pLength # 1]; IF cd.pLength # 1 THEN BEGIN -- we almost certainly had to add something -- so this is not as awful as it seems tvar: VarComponent ← Stack.TempStore[2]; P5U.Out1[FOpCodes.qLI, bWords]; P5L.LoadComponent[tvar]; END; BEGIN -- to define BltOp BltOp: ARRAY [1..2] OF BYTE = [FOpCodes.qBLT, FOpCodes.qBLTL]; P5U.Out0[BltOp[cd.pLength]]; END; IF fillBits # 0 THEN BEGIN usedBits: CARDINAL = eCount * grain; offset ← tOffset; P5L.FieldOfComponent[var: @offset, wd: usedBits / wordlength, bd: usedBits MOD wordlength, bSize: fillBits]; ConstructCountDown[]; ConsAssign[@offset, MPtr.tC0]; END; END; ConstructExp: PUBLIC PROCEDURE [t: Tree.Link, node: Tree.Index] RETURNS [Lexeme] = BEGIN -- generate code for constructor expression r, rr: VarIndex; tsei: RecordSEIndex; wa: BOOLEAN ← FALSE; fa: PROCEDURE [ISEIndex] RETURNS [BitAddress, CARDINAL]; saveCd: ConsDestination = cd; offset: frame VarComponent; nwords: CARDINAL; packedDest: VarIndex ← VarNull; tsei ← LOOPHOLE[tb[node].info, RecordSEIndex]; nwords ← WordsForType[tsei]; wa ← P5U.WordAligned[tsei]; IF t = Tree.Null AND wa AND nwords <= MaxParmsInStack THEN BEGIN -- can build in stack P5.ConstructOnStack[tb[node].son[2], tsei]; RETURN[P5L.TOSLex[nwords]]; END; cd ← [ignoreSafen: t = Tree.Null OR t.tag = symbol]; -- + many defaults tb[node].son[2] ← TreeOps.UpdateList[tb[node].son[2], CountDups]; r ← P5L.VarForLex[IF t = Tree.Null THEN P5.GenTempLex[nwords] ELSE P5.Exp[t]]; WITH cc: cb[r] SELECT FROM ind => WITH cc SELECT FROM packed => BEGIN var: VarComponent; packedDest ← r; var ← P5L.ComponentForLex[P5.GenTempLex[1]]; r ← P5L.OVarItem[var]; END; ENDCASE; ENDCASE; rr ← SetConsDest[r, TRUE]; offset ← [wSize: cd.wSize, bSize: cd.bSize, space: frame[]]; fa ← IF seb[tsei].argument THEN SymbolOps.FnField ELSE P5U.FieldAddress; MainConstruct[tb[node].son[2], tsei, fa, @offset]; IF cd.remaining # 0 THEN SIGNAL ConstructionError; IF packedDest # VarNull THEN [] ← P5L.VarVarAssign[packedDest, P5L.CopyVarItem[rr], FALSE]; cd ← saveCd; RETURN [[bdo[rr]]]; END; TransferConstruct: PUBLIC PROCEDURE [lex: Lexeme, t: Tree.Link, tsei: CSEIndex] = BEGIN -- generate code for construct statement -- lex is TOSAddrLex for allocated large parameter record saveCd: ConsDestination = cd; offset: frame VarComponent; cd ← [ignoreSafen: t.tag = symbol]; -- + many defaults t ← TreeOps.UpdateList[t, CountDups]; IF cd.remaining = 0 THEN RETURN; [] ← SetConsDest[P5L.VarForLex[lex], FALSE]; cd.remaining ← cd.remaining + 1; offset ← [wSize: cd.wSize, bSize: cd.bSize, space: frame[]]; MainConstruct[t, tsei, SymbolOps.FnField, @offset]; [] ← LoadPointer[0]; cd ← saveCd; RETURN END; Construct: PUBLIC PROCEDURE [t: Tree.Link, node: Tree.Index] = BEGIN -- generate code for construct statement tsei: RecordSEIndex; r, rr: VarIndex; saveCd: ConsDestination = cd; offset: frame VarComponent; fa: PROCEDURE [ISEIndex] RETURNS [BitAddress, CARDINAL]; packedDest: VarIndex ← VarNull; cd ← [ignoreSafen: t.tag = symbol]; -- + many defaults tb[node].son[2] ← TreeOps.UpdateList[tb[node].son[2], CountDups]; IF cd.remaining = 0 THEN RETURN; tsei ← LOOPHOLE[tb[node].info]; fa ← IF seb[tsei].argument THEN SymbolOps.FnField ELSE P5U.FieldAddress; r ← P5L.VarForLex[P5.Exp[t]]; WITH cc: cb[r] SELECT FROM ind => WITH cc SELECT FROM packed => BEGIN var: VarComponent; packedDest ← r; var ← P5L.ComponentForLex[P5.GenTempLex[1]]; r ← P5L.OVarItem[var]; END; ENDCASE; ENDCASE; rr ← SetConsDest[r, packedDest # VarNull]; offset ← [wSize: cd.wSize, bSize: cd.bSize, space: frame[]]; MainConstruct[tb[node].son[2], tsei, fa, @offset]; IF cd.remaining # 0 THEN SIGNAL ConstructionError; IF packedDest # VarNull THEN [] ← P5L.VarVarAssign[packedDest, rr, FALSE]; cd ← saveCd; RETURN END; VariantConstruct: PUBLIC PROCEDURE [node: Tree.Index] = BEGIN -- generate code for construct statement r: VarIndex; saveCd: ConsDestination = cd; offset: frame VarComponent; t1: Tree.Link ← tb[node].son[1]; rootSei: RecordSEIndex; WITH t1 SELECT FROM subtree => t1 ← tb[index].son[1]; -- always a dollar node ENDCASE => P5.P5Error[592]; cd ← [ignoreSafen: t1.tag = symbol]; -- + many defaults tb[node].son[2] ← TreeOps.UpdateList[tb[node].son[2], CountDups]; IF cd.remaining = 0 THEN RETURN; rootSei ← SymbolOps.RecordRoot[LOOPHOLE[P5U.OperandType[t1]]]; r ← P5L.VarForLex[P5.Exp[t1]]; WITH cc: cb[r] SELECT FROM ind => WITH cc SELECT FROM packed => SIGNAL CPtr.CodeNotImplemented; ENDCASE; ENDCASE; [] ← SetConsDest[r, FALSE]; offset ← [wSize: cd.wSize, bSize: cd.bSize, space: frame[]]; WITH tb[node].son[2] SELECT FROM subtree => UnionConstruct[index, rootSei, @offset]; ENDCASE; IF cd.remaining # 0 THEN SIGNAL ConstructionError; cd ← saveCd; RETURN END; All: PUBLIC PROCEDURE [t: Tree.Link, node: Tree.Index] = BEGIN -- array initialization r: VarIndex; saveCd: ConsDestination = cd; -- necessary in an inline offset: frame VarComponent; asei: Symbols.ArraySEIndex = tb[node].info; cd ← [ignoreSafen: t.tag = symbol]; -- + many defaults IF seb[asei].oldPacked AND SymbolOps.BitsForType[seb[asei].componentType] <= 8 THEN cd.remaining ← 1 ELSE tb[node].son[1] ← TreeOps.UpdateList[tb[node].son[1], CountDups]; r ← P5L.VarForLex[P5.Exp[t]]; [] ← SetConsDest[r, FALSE]; offset ← [wSize: cd.wSize, bSize: cd.bSize, space: frame[]]; AllConstruct[node, @offset]; IF cd.remaining # 0 THEN SIGNAL ConstructionError; cd ← saveCd; RETURN END; AllExp: PUBLIC PROCEDURE [t: Tree.Link, node: Tree.Index] RETURNS [Lexeme] = BEGIN -- array (expression)initialization r, rr: VarIndex; saveCd: ConsDestination = cd; offset: frame VarComponent; awords: CARDINAL = WordsForType[tb[node].info]; asei: Symbols.ArraySEIndex = tb[node].info; cd ← [ignoreSafen: t = Tree.Null OR t.tag = symbol]; -- + many defaults IF seb[asei].oldPacked AND SymbolOps.BitsForType[seb[asei].componentType] <= 8 THEN cd.remaining ← 1 ELSE tb[node].son[1] ← TreeOps.UpdateList[tb[node].son[1], CountDups]; r ← P5L.VarForLex[IF t = Tree.Null THEN P5.GenTempLex[awords] ELSE P5.Exp[t]]; rr ← SetConsDest[r, TRUE]; offset ← [wSize: cd.wSize, bSize: cd.bSize, space: frame[]]; AllConstruct[node, @offset]; IF cd.remaining # 0 THEN SIGNAL ConstructionError; cd ← saveCd; RETURN[[bdo[rr]]] END; END.