DIRECTORY Alloc USING [FreeChunk, GetChunk, Handle, Notifier, Words], Code USING [bodyStartLoc, codeptr, fileLoc, xtracting, xtractsei, ZEROlexeme], CodeDefs USING [Base, Byte, CCIndex, CCItem, CCNull, ChunkIndex, CodeCCIndex, CodeChunkType, codeType, JumpCCIndex, JumpCCNull, JumpType, LabelCCIndex, LabelCCNull, Lexeme, OpWordCount, RelSourceLoc], ComData USING [typeSTRING], FOpCodes USING [qJ, qJREL, qLI], LiteralOps USING [Find, FindDescriptor, Value], OpTableDefs USING [InstLength], P5 USING [NumberOfParams, P5Error, PushEffect], P5U USING [], PackageSymbols USING [ConstRecord, constType, WordIndex], PrincOps USING [FrameVec], SourceMap USING [Loc, nullLoc, Cons, Delta, Val], Stack USING [Check], SymbolOps USING [FirstCtxSe, NextSe, NormalType, RecordRoot, TypeRoot, UnderType, WordsForType], Symbols USING [Base, BitAddress, CSEIndex, CTXIndex, ISEIndex, ISENull, RecordSEIndex, SEIndex, SENull, seType, typeANY, typeTYPE, WordLength], Table USING [Base, Limit], Tree USING [Base, Index, Link, Null, NullIndex, treeType], TreeOps USING [PopTree, PushNode, PushTree, ScanList, SetInfo]; CgenUtil: PROGRAM IMPORTS Alloc, MPtr: ComData, CPtr: Code, LiteralOps, OpTableDefs, P5, SourceMap, Stack, SymbolOps, TreeOps EXPORTS P5U = BEGIN OPEN SymbolOps, CodeDefs; BitAddress: TYPE = Symbols.BitAddress; CSEIndex: TYPE = Symbols.CSEIndex; ISEIndex: TYPE = Symbols.ISEIndex; ISENull: ISEIndex = Symbols.ISENull; RecordSEIndex: TYPE = Symbols.RecordSEIndex; SEIndex: TYPE = Symbols.SEIndex; SENull: SEIndex = Symbols.SENull; WordLength: CARDINAL = Symbols.WordLength; table: Alloc.Handle _ NIL; tb: Tree.Base; -- tree base (local copy) seb: Symbols.Base; -- semantic entry base (local copy) cb: CodeDefs.Base; -- code base (local copy) cstb: Table.Base; -- constant table base (local copy) CgenUtilNotify: PUBLIC Alloc.Notifier = BEGIN -- called by allocator whenever table area is repacked seb _ base[Symbols.seType]; tb _ base[Tree.treeType]; cb _ base[codeType]; cstb _ base[PackageSymbols.constType]; END; AllocCodeCCItem: PUBLIC PROC [n: [0..3]] RETURNS [c: CodeCCIndex] = BEGIN c _ GetChunk[CCItem.code.SIZE + n]; cb[c] _ CCItem[free: FALSE, flink: CCNull, blink: CCNull, ccvalue: code[inst: 0, realinst: FALSE, isize: 0, fill: 0, parameters: ]]; LinkCCItem[c]; RETURN END; BitsForOperand: PUBLIC PROC [t: Tree.Link] RETURNS [CARDINAL] = BEGIN RETURN [WITH t SELECT FROM literal => WordLength, -- not always TRUE, but good enough ENDCASE => BitsForType[OperandType[t]]] END; BitsForType: PUBLIC PROC [sei: SEIndex] RETURNS [CARDINAL] = BEGIN csei: CSEIndex = UnderType[sei]; RETURN [WITH seb[csei] SELECT FROM record => length, ENDCASE => CARDINAL[WordsForType[csei]]*WordLength] END; CCellAlloc: PUBLIC PROC [t: CodeChunkType] = BEGIN -- allocates a cell for other than code or label c: CCIndex; nwords: CARDINAL; SELECT t FROM code => P5.P5Error[262]; label => P5.P5Error[263]; jump => nwords _ CCItem.jump.SIZE; other => nwords _ CCItem.other.SIZE; -- NB: not relSource OR absSource ENDCASE; c _ GetChunk[nwords]; SELECT t FROM jump => cb[c] _ CCItem[free: FALSE, flink: , blink: , ccvalue: jump[,,,,,,,]]; other => cb[c] _ CCItem[free: FALSE, flink: , blink: , ccvalue: other[obody: ]]; ENDCASE; LinkCCItem[c]; END; CgenUtilInit: PUBLIC PROC [ownTable: Alloc.Handle] = BEGIN table _ ownTable; CPtr.ZEROlexeme _ Lexeme[literal[word[LiteralOps.Find[0].lti]]]; CPtr.fileLoc _ SourceMap.Cons[0]; END; ComputeFrameSize: PUBLIC PROC [fs: CARDINAL] RETURNS [CARDINAL] = BEGIN -- finds alloc-vector index for frame of size fs OPEN PrincOps; FOR fx: CARDINAL IN [0..FrameVec.LENGTH) DO IF fs <= FrameVec[fx] THEN RETURN [fx] ENDLOOP; ERROR END; CreateLabel: PUBLIC PROC RETURNS [c: LabelCCIndex] = BEGIN -- allocates and inserts a label at codeptr c _ LabelAlloc[]; InsertLabel[c]; END; DeleteCell: PUBLIC PROC [c: CCIndex] = BEGIN -- deletes cell from code stream nwords: CARDINAL; IF cb[c].blink # CCNull THEN cb[cb[c].blink].flink _ cb[c].flink; IF cb[c].flink # CCNull THEN cb[cb[c].flink].blink _ cb[c].blink; nwords _ WITH cc: cb[c] SELECT FROM code => ParamCount[LOOPHOLE[c]] + CCItem.code.SIZE, label => CCItem.label.SIZE, jump => CCItem.jump.SIZE, other => WITH cc SELECT FROM absSource => CCItem.other.absSource.SIZE, relSource => CCItem.other.relSource.SIZE, ENDCASE => CCItem.other.SIZE, -- NB: see CCellAllocate ENDCASE => ERROR; FreeChunk[c, nwords]; END; EnumerateCaseArms: PUBLIC PROC [node: Tree.Index, action: PROC [t: Tree.Link]] = BEGIN ProcessItem: PROC [t: Tree.Link] = BEGIN inode: Tree.Index; WITH t SELECT FROM subtree => inode _ index; ENDCASE; SELECT tb[inode].name FROM item, casetest => action[tb[inode].son[2]]; caseswitch => TreeOps.ScanList[tb[inode].son[3], ProcessItem]; ENDCASE; END; TreeOps.ScanList[tb[node].son[2], ProcessItem]; IF tb[node].son[3] # Tree.Null THEN action[tb[node].son[3]]; END; FreeChunk: PUBLIC PROC [i: CodeDefs.ChunkIndex, size: CARDINAL] = BEGIN FOR p: LIST OF MonitorRecord _ monList, p.rest WHILE p # NIL DO IF p.first.cell = i AND p.first.action = free THEN ERROR; ENDLOOP; table.FreeChunk[LOOPHOLE[i], size, codeType]; END; FullWordBits: PUBLIC PROC [bits: CARDINAL] RETURNS [CARDINAL] = BEGIN RETURN [((bits+WordLength-1)/WordLength) * WordLength] END; GetChunk: PUBLIC PROC [size: CARDINAL] RETURNS [c: CodeDefs.ChunkIndex] = BEGIN c _ LOOPHOLE[table.GetChunk[size, codeType]]; FOR p: LIST OF MonitorRecord _ monList, p.rest WHILE p # NIL DO IF p.first.cell = c AND p.first.action = allocate THEN ERROR; ENDLOOP; RETURN [c] END; InsertLabel: PUBLIC PROC [c: LabelCCIndex] = LinkCCItem; LabelAlloc: PUBLIC PROC RETURNS [c: LabelCCIndex] = BEGIN -- gets a chunk for a label but does not insert it in stream c _ GetChunk[CCItem.label.SIZE]; cb[c] _ CCItem[free: FALSE, flink: , blink: , ccvalue: label[labelseen: FALSE, labelinfo: generating[fillword: , jumplist: JumpCCNull]]]; RETURN END; LinkCCItem: PROC[c: CCIndex] = BEGIN -- inserts a CCItem in list @ codeptr IF CPtr.codeptr # CCNull THEN BEGIN cb[c].flink _ cb[CPtr.codeptr].flink; IF cb[CPtr.codeptr].flink # CCNull THEN cb[cb[CPtr.codeptr].flink].blink _ c; cb[CPtr.codeptr].flink _ c; END ELSE cb[c].flink _ CCNull; cb[c].blink _ CPtr.codeptr; CPtr.codeptr _ c; END; LongTreeAddress: PUBLIC PROC [t: Tree.Link] RETURNS [long: BOOL _ FALSE] = BEGIN node: Tree.Index; WITH t SELECT FROM subtree => BEGIN node _ index; IF node # Tree.NullIndex THEN SELECT tb[node].name FROM loophole, cast, openx, pad, chop => long _ LongTreeAddress[tb[node].son[1]]; dot, uparrow, dindex, seqindex, dollar, index, new, reloc => long _ tb[node].attr2; assignx => WITH tb[node].son[2] SELECT FROM subtree => IF tb[index].name = mwconst THEN long _ LongTreeAddress[tb[node].son[1]] ELSE long _ LongTreeAddress[tb[node].son[2]]; ENDCASE => long _ LongTreeAddress[tb[node].son[2]]; ifx => long _ LongTreeAddress[tb[node].son[2]] OR LongTreeAddress[tb[node].son[3]]; casex => BEGIN LongArm: PROC [t: Tree.Link] = {long _ long OR LongTreeAddress[t]}; EnumerateCaseArms[node, LongArm]; END; ENDCASE => NULL; END; ENDCASE => NULL; RETURN END; MakeLongTreeLiteral: PUBLIC PROC [d: DESCRIPTOR FOR ARRAY OF WORD, type: CSEIndex] RETURNS [Tree.Link] = BEGIN TreeOps.PushTree[[literal[LiteralOps.FindDescriptor[d]]]]; TreeOps.PushNode[mwconst, 1]; TreeOps.SetInfo[type]; RETURN [TreeOps.PopTree[]] END; MakeTreeLiteral: PUBLIC PROC [val: WORD] RETURNS [Tree.Link] = BEGIN RETURN [[literal[LiteralOps.Find[val]]]] END; MarkedType: PUBLIC PROC [type: SEIndex] RETURNS [CSEIndex] = BEGIN subType: CSEIndex = NormalType[UnderType[type]]; RETURN [WITH t: seb[subType] SELECT FROM ref => UnderType[TypeRoot[t.refType]], transfer => subType, ENDCASE => Symbols.typeANY] END; MonitorAction: TYPE = {allocate, free}; MonitorRecord: TYPE = RECORD [cell: CCIndex, action: MonitorAction]; monList: LIST OF MonitorRecord _ NIL; Monitor: PROC [cell: CCIndex, action: MonitorAction] = BEGIN monList _ CONS[[cell, action], monList]; END; NextVar: PUBLIC PROC [sei: ISEIndex] RETURNS [ISEIndex] = BEGIN -- starting at sei returns first variable on ctx-list RETURN [SELECT TRUE FROM (sei = ISENull) => ISENull, (seb[sei].idType # Symbols.typeTYPE) => sei, ENDCASE => NextVar[NextSe[sei]]] END; NilTree: PUBLIC PROC [type: CSEIndex] RETURNS [Tree.Link] = BEGIN SELECT SymbolOps.WordsForType[type] FROM 1 => RETURN[MakeTreeLiteral[0]]; 2 => BEGIN zeros: ARRAY [0..2) OF WORD _ [0, 0]; RETURN[MakeLongTreeLiteral[DESCRIPTOR[zeros], type]]; END; ENDCASE => ERROR; END; OperandType: PUBLIC PROC [t: Tree.Link] RETURNS [sei: CSEIndex] = BEGIN -- compute type of tree RETURN [WITH e:t SELECT FROM symbol => UnderType[seb[e.index].idType], literal => IF e.index.litTag = string THEN MPtr.typeSTRING ELSE ERROR, subtree => IF e = Tree.Null THEN IF CPtr.xtracting THEN UnderType[seb[CPtr.xtractsei].idType] ELSE ERROR ELSE UnderType[tb[e.index].info], ENDCASE => ERROR] END; Out0: PUBLIC PROC [i: Byte] = BEGIN -- outputs an parameter-less instruction c: CodeCCIndex; pushEffect: CARDINAL = P5.PushEffect[i]; Stack.Check[i]; IF P5.NumberOfParams[i] # 0 THEN P5.P5Error[257]; c _ AllocCodeCCItem[0]; cb[c].inst _ i; END; Out1: PUBLIC PROC [i: Byte, p1: WORD] = BEGIN -- outputs an one-parameter instruction c: CodeCCIndex; pushEffect: CARDINAL = P5.PushEffect[i]; Stack.Check[i]; IF P5.NumberOfParams[i] # 1 THEN P5.P5Error[258]; c _ AllocCodeCCItem[1]; cb[c].inst _ i; cb[c].parameters[1] _ p1; END; Out2: PUBLIC PROC [i: Byte, p1, p2: WORD] = BEGIN -- outputs an two-parameter instruction c: CodeCCIndex; pushEffect: CARDINAL = P5.PushEffect[i]; Stack.Check[i]; IF P5.NumberOfParams[i] # 2 THEN P5.P5Error[259]; c _ AllocCodeCCItem[2]; cb[c].inst _ i; cb[c].parameters[1] _ p1; cb[c].parameters[2] _ p2; END; Out3: PUBLIC PROC [i: Byte, p1, p2, p3: WORD] = BEGIN -- outputs an three-parameter instruction c: CodeCCIndex; pushEffect: CARDINAL = P5.PushEffect[i]; Stack.Check[i]; IF P5.NumberOfParams[i] # 3 THEN P5.P5Error[260]; c _ AllocCodeCCItem[3]; cb[c].inst _ i; cb[c].parameters[1] _ p1; cb[c].parameters[2] _ p2; cb[c].parameters[3] _ p3; END; OutJump: PUBLIC PROC [jt: JumpType, l: LabelCCIndex] = BEGIN -- outputs a jump-type code ceel into the code stream Stack.Check[SELECT jt FROM Jump, JumpA, JumpC, JumpCA, JumpRet => FOpCodes.qJ, ENDCASE => FOpCodes.qJREL]; CCellAlloc[jump]; WITH cb[CPtr.codeptr] SELECT FROM jump => BEGIN fixedup _ FALSE; completed _ FALSE; jtype _ jt; destlabel _ l; IF l # LabelCCNull THEN BEGIN thread _ cb[l].jumplist; cb[l].jumplist _ LOOPHOLE[CPtr.codeptr, JumpCCIndex]; END ELSE thread _ JumpCCNull; END; ENDCASE END; OutSource: PUBLIC PROC [index: SourceMap.Loc] = BEGIN c: CCIndex; relIndex: CARDINAL; IF index # SourceMap.nullLoc AND index.Val[] >= CPtr.bodyStartLoc.Val[] AND (relIndex _ index.Delta[CPtr.bodyStartLoc]) IN RelSourceLoc THEN BEGIN c _ GetChunk[CCItem.other.relSource.SIZE]; cb[c] _ [free: FALSE, flink: , blink: , ccvalue: other[relSource[relLoc: relIndex]]]; END ELSE BEGIN c _ GetChunk[CCItem.other.absSource.SIZE]; cb[c] _ [free: FALSE, flink: , blink: , ccvalue: other[absSource[loc: index]]]; END; LinkCCItem[c]; END; ParamCount: PUBLIC PROC [c: CodeCCIndex] RETURNS [CARDINAL] = BEGIN RETURN [SELECT TRUE FROM (cb[c].isize # 0) => cb[c].isize-1, cb[c].realinst => OpTableDefs.InstLength[cb[c].inst]-1, ENDCASE => P5.NumberOfParams[cb[c].inst]] END; PrevVar: PUBLIC PROC [ssei, sei : ISEIndex] RETURNS [ISEIndex] = BEGIN -- returns vars in reverse order as those returned by NextVar psei: ISEIndex _ NextVar[ssei]; rsei: ISEIndex; IF psei = sei THEN RETURN [psei]; UNTIL psei = sei DO rsei _ psei; psei _ NextVar[NextSe[psei]] ENDLOOP; RETURN [rsei]; END; PushLitVal: PUBLIC PROC [v: UNSPECIFIED] = BEGIN -- forces a constant onto the stack Out1[FOpCodes.qLI, v]; END; RecordConstant: PUBLIC PROC [offset: PackageSymbols.WordIndex, length: CARDINAL] = BEGIN OPEN PackageSymbols; csti: Table.Base RELATIVE POINTER [0..Table.Limit) TO ConstRecord = table.Words[constType, ConstRecord.SIZE]; cstb[csti] _ [offset: offset, length: length]; END; ReferentType: PUBLIC PROC [type: SEIndex] RETURNS [SEIndex] = BEGIN subType: CSEIndex = NormalType[UnderType[type]]; RETURN [WITH t: seb[subType] SELECT FROM ref => t.refType, ENDCASE => Symbols.typeANY] END; TreeLiteral: PUBLIC PROC [t: Tree.Link] RETURNS [BOOL] = BEGIN RETURN [WITH t SELECT FROM literal => index.litTag = word, subtree => SELECT tb[index].name FROM cast => TreeLiteral[tb[index].son[1]], mwconst => TRUE, ENDCASE => FALSE, ENDCASE => FALSE] END; TreeLiteralValue: PUBLIC PROC [t: Tree.Link] RETURNS [WORD] = BEGIN RETURN [WITH e:t SELECT FROM literal => WITH e.index SELECT FROM word => LiteralOps.Value[lti], ENDCASE => ERROR, subtree => SELECT tb[e.index].name FROM cast, mwconst => TreeLiteralValue[tb[e.index].son[1]], ENDCASE => ERROR, ENDCASE => ERROR] END; TypeForTree: PUBLIC PROC [t: Tree.Link] RETURNS [SEIndex] = BEGIN RETURN [WITH t SELECT FROM subtree => tb[index].info, symbol => index, ENDCASE => ERROR] END; UnMonitor: PROC [cell: CCIndex, action: MonitorAction] = BEGIN IF monList = NIL THEN RETURN; IF monList.first.cell = cell AND monList.first.action = action THEN {monList _ monList.rest; RETURN}; FOR p: LIST OF MonitorRecord _ monList, p.rest UNTIL p.rest = NIL DO IF p.rest.first.cell = cell AND p.rest.first.action = action THEN {p.rest _ p.rest.rest; RETURN}; ENDLOOP; END; VariantTag: PUBLIC PROC [type: SEIndex, ctx: Symbols.CTXIndex] RETURNS [WORD] = BEGIN next: SEIndex; FOR sei: SEIndex _ type, next UNTIL sei = SENull DO WITH se: seb[sei] SELECT FROM id => BEGIN IF se.idCtx = ctx THEN RETURN [se.idValue]; next _ se.idInfo; END; ENDCASE => EXIT; ENDLOOP; ERROR END; WordAligned: PUBLIC PROC [tsei: RecordSEIndex] RETURNS [BOOL] = BEGIN -- sees if a word-aligned record (never TRUE for a variant record) sei: ISEIndex; wa: INTEGER _ 0; a: BitAddress; tsei _ RecordRoot[tsei]; IF seb[tsei].hints.variant THEN RETURN [FALSE]; IF seb[tsei].argument THEN RETURN [TRUE]; sei _ NextVar[FirstCtxSe[seb[tsei].fieldCtx]]; UNTIL sei = ISENull DO a _ seb[sei].idValue; IF a.bd # 0 THEN RETURN [FALSE]; IF a.wd < wa THEN RETURN [FALSE]; wa _ a.wd; sei _ NextVar[NextSe[sei]]; ENDLOOP; RETURN [TRUE] END; WordsForOperand: PUBLIC PROC [t: Tree.Link] RETURNS [OpWordCount] = BEGIN -- compute number of words for storing value of tree RETURN [WITH t SELECT FROM literal => 1, -- multiwords will be subtrees symbol => WordsForSei[seb[index].idType], ENDCASE => OpWordCount[WordsForType[OperandType[t]]]] END; WordsForSei: PUBLIC PROC [sei: SEIndex] RETURNS [OpWordCount] = BEGIN RETURN [IF sei # SENull THEN OpWordCount[WordsForType[UnderType[sei]]] ELSE 0] END; WordsForString: PUBLIC PROC [nChars: CARDINAL] RETURNS [CARDINAL] = BEGIN -- computed for the object machine RETURN [(nChars+1)/2 + 2] END; END. &CgenUtil.mesa, Copyright c 1985 by Xerox Corporation. All rights reserved. Sweet, May 24, 1980 11:35 AM Satterthwaite, April 8, 1986 2:07:54 pm PST Maxwell, August 2, 1983 3:15 pm Russ Atkinson (RRA) March 7, 1985 1:49:01 am PST imported definitions always true for an argument record ΚΜ˜codešœ™Kšœ Οmœ1™Kšžœ˜—Kšžœ˜K˜—K˜/Kšžœžœ˜Kšž˜Kšžœ"˜(Kšžœ˜K˜—š  œžœžœžœ ˜˜DK˜K˜Kšžœ žœžœ˜!Kšžœ žœ+žœ˜FKšžœ˜Kšžœ˜K˜—š  œžœžœž œ˜*KšžœŸ#˜)K˜Kšžœ˜K˜K˜—š œžœžœ,žœ˜RKšžœžœ˜šœžœžœžœ˜DKšœ#žœ˜)—K˜.Kšžœ˜K˜K˜—š  œžœžœžœ ˜=Kšž˜K˜0šžœžœžœž˜(K˜Kšžœ˜—Kšžœ˜K˜K˜—š   œžœžœžœžœ˜8Kšž˜šžœžœžœž˜K˜˜ šžœž˜K˜&Kšœ žœ˜Kšžœžœ˜——Kšžœžœ˜—Kšžœ˜K˜—š  œžœžœžœžœ˜=Kšž˜šžœžœžœž˜˜ šžœ žœž˜K˜Kšžœžœ˜——˜ šžœž˜K˜7Kšžœžœ˜——Kšžœžœ˜—Kšžœ˜K˜—š  œžœžœžœ ˜;Kšž˜šžœžœžœž˜K˜K˜Kšžœžœ˜—Kšžœ˜K˜—š  œžœ)˜8Kšž˜Kšžœ žœžœžœ˜šžœžœ˜?Kšžœžœ˜&—š žœžœžœ!žœ žœž˜Dšžœžœ˜=Kšžœžœ˜$—Kšžœ˜—Kšžœ˜K˜—š   œžœžœ(žœžœ˜OKšž˜K˜šžœžœž˜3šžœžœž˜˜Kšž˜Kšžœžœžœ˜+K˜Kšžœ˜—Kšžœžœ˜—Kšžœ˜—Kšž˜Kšžœ˜K˜—š   œžœžœžœžœ˜?šžœŸB˜HKšœ"™"—K˜Kšœžœ˜K˜K˜Kšžœžœžœžœ˜/Kšžœžœžœžœ˜)K˜.šžœž˜K˜Kšžœ žœžœžœ˜ Kšžœ žœžœžœ˜!K˜ K˜Kšžœ˜—Kšžœžœ˜ Kšžœ˜K˜—š œžœžœžœ˜CKšžœŸ4˜:šžœžœžœž˜KšœŸ˜,K˜)Kšžœ.˜5—Kšžœ˜K˜—š  œžœžœžœ˜?Kšž˜Kšžœžœžœ+žœ˜NKšžœ˜K˜—š  œžœžœ žœžœžœ˜CKšžœŸ"˜)Kšžœ˜Kšžœ˜K˜—Kšžœ˜K˜——…—9ΜNΎ