-- file CountingImpl.Mesa -- last edited by Satterthwaite, April 26, 1983 2:50 pm -- last change by Russ Atkinson, October 11, 1980 2:12 PM DIRECTORY Alloc: TYPE USING [Notifier], CodeDefs: TYPE USING [ Base, BoVarIndex, codeType, JumpType, LabelCCIndex, Lexeme, NullLex, StoreOptions, VarComponent, VarIndex, VarNull], ComData: TYPE USING [switches, typeRefANY], Counting: TYPE USING [], FOpCodes: TYPE USING [ qBLTL, qBLZL, qDUP, qICDL, qKFCB, qLP, qPUSH, qNILCKL, qRL, qRD, qSFC, qSUB, qWCDL, qWL], P5: TYPE USING [CallCatch, Exp, GenTempLex, PushLex, PushRhs, SAssign, SysCall], P5L: TYPE USING [ AllLoaded, CopyToTemp, CopyVarItem, EasilyLoadable, InCode, GenAdd, LoadAddress, LoadComponent, LoadVar, MakeBo, OVarItem, ReleaseVarItem, ReusableCopies, StoreVar, TOSAddrLex, VarAlignment, VarVarAssign, VarForLex, Words], P5U: TYPE USING [ InsertLabel, LabelAlloc, Out0, Out1, OutJump, PushLitVal, TreeLiteral, WordsForSei], RTSD: TYPE USING [sAssignComposite, sAssignCompositeNew, SD, sSystemZone], Stack: TYPE USING [Decr, DeleteToMark, Dump, Incr, Load, Mark, TempStore, Top], SymbolOps: TYPE USING [ FirstCtxSe, NextSe, RCType, TypeRoot, UnderType, WordsForType], Symbols: TYPE USING [ Base, CSEIndex, ISEIndex, lZ, RecordSEIndex, RefClass, SEIndex, seType], SymLiteralOps: TYPE USING [TypeRef], Tree: TYPE USING [Link, Null], TreeOps: TYPE USING [FreeTree, ScanList]; CountingImpl: PROGRAM IMPORTS MPtr: ComData, P5, P5L, P5U, Stack, SymbolOps, SymLiteralOps, TreeOps EXPORTS Counting, CodeDefs = { OPEN CodeDefs, Counting, Symbols; seb: Symbols.Base; -- se base (local copy) cb: CodeDefs.Base; -- code base (local copy) CountingNotify: PUBLIC Alloc.Notifier = { -- called by allocator whenever table area is repacked seb ← base[seType]; cb ← base[codeType]}; CheckArgRefs: PUBLIC PROC [t: Tree.Link, rsei: RecordSEIndex] RETURNS [safe: BOOL←TRUE] = BEGIN IF seb[rsei].hints.refField THEN BEGIN sei: ISEIndex ← SymbolOps.FirstCtxSe[seb[rsei].fieldCtx]; TestField: PROC [t: Tree.Link] = BEGIN IF SymbolOps.RCType[SymbolOps.UnderType[seb[sei].idType]] # none AND ~P5U.TreeLiteral[t] THEN safe ← FALSE; sei ← SymbolOps.NextSe[sei]; END; TreeOps.ScanList[t, TestField]; END; RETURN END; Allocate: PUBLIC PROC [ zone: Tree.Link, type: SEIndex, catch: Tree.Link, pushSize: PROC] = { -- Allocate generates code for space allocation from counted zones -- first, generate code to perform the allocation nwords: CARDINAL = SymbolOps.WordsForType[type]; sizeVar: VarIndex ← VarNull; zoneVar, copyVar: VarIndex; topVar: VarIndex ← VarNull; initRC: RefClass = SymbolOps.RCType[SymbolOps.UnderType[type]]; typeTree: Tree.Link ← SymLiteralOps.TypeRef[SymbolOps.TypeRoot[type], FALSE]; Stack.Dump[]; Stack.Mark[]; IF zone = Tree.Null THEN LoadSystemZone[] ELSE { zoneVar ← P5L.VarForLex[P5.Exp[zone]]; [first: zoneVar, next: copyVar] ← P5L.ReusableCopies[zoneVar, load, FALSE]; P5L.LoadVar[zoneVar]}; IF pushSize # NIL THEN { pushSize[]; -- (must save it for later) P5U.Out0[FOpCodes.qDUP]; sizeVar ← StackTemp[1]} ELSE P5U.PushLitVal[nwords]; P5.PushRhs[typeTree]; typeTree ← TreeOps.FreeTree[typeTree]; IF zone = Tree.Null THEN LoadSystemZone[] ELSE { P5L.LoadVar[copyVar]; IF ~MPtr.switches['a] THEN P5U.Out0[FOpCodes.qNILCKL]}; P5U.Out1[FOpCodes.qRL, 0]; Stack.DeleteToMark[]; Stack.Incr[1]; P5U.Out0[FOpCodes.qSFC]; P5.CallCatch[catch]; Stack.Incr[2]; -- if size is in a variable and we are RC, then clear the world to NIL IF initRC # none AND pushSize # NIL THEN { IF nwords = 0 OR sizeVar = VarNull THEN ERROR; IF MPtr.switches['m] THEN {CopyLoad[sizeVar]; P5U.Out0[FOpCodes.qBLZL]} ELSE { topVar ← StackTemp[2]; P5U.PushLitVal[0]; CopyLoad[topVar]; P5U.Out1[FOpCodes.qWL, 0]; CopyLoad[topVar]; CopyLoad[sizeVar]; P5U.PushLitVal[1]; P5U.Out0[FOpCodes.qSUB]; DoubleIncr[topVar, 1]; P5U.Out0[FOpCodes.qBLTL]; CopyLoad[topVar]}}}; Free: PUBLIC PROC [var: VarIndex, counted: BOOL, zone, catch: Tree.Link] = { -- emit code for zone.FREE[@ var ! catch] c0: VarIndex ← P5L.OVarItem[[wSize: 2, space: const[d1:0, d2:0]]]; bor: BoVarIndex ← P5L.MakeBo[var]; r, rr, zoneVar, copyVar: VarIndex; cb[bor].base ← P5L.EasilyLoadable[cb[bor].base, load]; rr ← P5L.CopyVarItem[bor]; r ← P5L.OVarItem[P5L.CopyToTemp[bor].var]; IF counted THEN [] ← VarVarAssignCounted[rr, c0, [counted: TRUE], MPtr.typeRefANY] ELSE [] ← P5L.VarVarAssign[rr, c0, FALSE]; Stack.Dump[]; Stack.Mark[]; IF zone = Tree.Null THEN LoadSystemZone[] ELSE { zoneVar ← P5L.VarForLex[P5.Exp[zone]]; [first: zoneVar, next: copyVar] ← P5L.ReusableCopies[zoneVar, load, FALSE]; P5L.LoadVar[zoneVar]}; P5L.LoadVar[r]; -- reload the REF IF zone = Tree.Null THEN LoadSystemZone[] ELSE { P5L.LoadVar[copyVar]; IF ~MPtr.switches['a] THEN P5U.Out0[FOpCodes.qNILCKL]}; P5U.Out1[FOpCodes.qRL, 1]; Stack.DeleteToMark[]; Stack.Incr[1]; P5U.Out0[FOpCodes.qSFC]; P5.CallCatch[catch]}; VarVarAssignCounted: PUBLIC PROC [ to, from: VarIndex, options: StoreOptions, type: SEIndex] RETURNS [l: Lexeme ← NullLex] = { nWords: CARDINAL = P5U.WordsForSei[type]; IF options.composite THEN { typeTree: Tree.Link ← SymLiteralOps.TypeRef[SymbolOps.UnderType[type]]; tempVar: VarIndex; LoadLongVarAddress[from]; IF options.expr THEN CopyLoad[tempVar ← StackTemp[2]]; LoadLongAddress[to]; P5.PushRhs[typeTree]; typeTree ← TreeOps.FreeTree[typeTree]; P5U.PushLitVal[nWords]; Stack.Load[Stack.Top[6], 6]; Stack.Decr[6]; -- Stack.LoadToDepth[6]; P5U.Out1[FOpCodes.qKFCB, IF options.init THEN RTSD.sAssignCompositeNew ELSE RTSD.sAssignComposite]; IF options.expr THEN l ← AddrVarToLex[tempVar, nWords]} ELSE { IF nWords # 2 THEN ERROR; -- somebody goofed! IF options.expr THEN { v: VarIndex; P5L.LoadVar[from]; v ← StackTemp[2]; CopyLoad[v]; l ← [bdo[v]]} ELSE { IF ~StackVar[from, nWords] OR ~P5L.AllLoaded[from] THEN P5L.LoadVar[from]}; -- anything above it is part of "to" StoreVarCounted[to, options]}; RETURN}; StoreVarCounted: PROC [r: VarIndex, options: StoreOptions] = { WCDOp: ARRAY BOOL OF [0..256) = [ FALSE: FOpCodes.qWCDL, TRUE: FOpCodes.qICDL]; alpha: CARDINAL ← 0; WITH cc: cb[r] SELECT FROM bo => { offset: VarComponent = cc.offset; WITH oo: offset SELECT FROM frame => IF oo.level = Symbols.lZ AND oo.wSize = 2 AND oo.bSize = 0 AND oo.bd = 0 THEN { P5L.LoadComponent[cc.base]; SELECT P5L.Words[cc.base.wSize, cc.base.bSize] FROM 1 => P5U.Out0[FOpCodes.qLP]; 2 => NULL; ENDCASE => ERROR; alpha ← oo.wd; P5L.ReleaseVarItem[r]} ELSE LoadLongAddress[r]; ENDCASE => LoadLongAddress[r]}; ENDCASE => LoadLongAddress[r]; Stack.Load[Stack.Top[4], 4]; -- REF + nWords P5U.Out1[WCDOp[options.init], alpha]}; FillCounted: PUBLIC PROC [ space, source: VarIndex, options: StoreOptions, type: Symbols.SEIndex] = { subType: CSEIndex = SymbolOps.UnderType[type]; wordsPerItem: CARDINAL = SymbolOps.WordsForType[subType]; nItems: CARDINAL = P5L.VarAlignment[space, load].wSize/wordsPerItem; countLex: se Lexeme = P5.GenTempLex[1]; ptrTemp: VarIndex; loopLabel: CodeDefs.LabelCCIndex = P5U.LabelAlloc[]; testLabel: LabelCCIndex = P5U.LabelAlloc[]; LoadLongAddress[space]; ptrTemp ← StackTemp[2]; Stack.Dump[]; P5U.PushLitVal[nItems]; Stack.Decr[1]; P5U.OutJump[Jump, testLabel]; P5U.InsertLabel[loopLabel]; -- top of the assignment loop IF SymbolOps.RCType[subType] = composite THEN { typeTree: Tree.Link ← SymLiteralOps.TypeRef[subType]; Stack.Mark[]; LoadLongVarAddress[source]; CopyLoad[ptrTemp]; P5.PushRhs[typeTree]; typeTree ← TreeOps.FreeTree[typeTree]; P5U.PushLitVal[wordsPerItem]; P5.SysCall[IF options.init THEN RTSD.sAssignCompositeNew ELSE RTSD.sAssignComposite]} ELSE { WCDOp: ARRAY BOOL OF [0..256) = [FALSE: FOpCodes.qWCDL, TRUE: FOpCodes.qICDL]; P5L.LoadVar[source]; CopyLoad[ptrTemp]; P5U.Out1[WCDOp[options.init], 0]}; DoubleIncr[ptrTemp, wordsPerItem]; -- update pointer P5L.StoreVar[ptrTemp]; P5.PushLex[countLex]; P5U.PushLitVal[1]; P5U.Out0[FOpCodes.qSUB]; P5U.InsertLabel[testLabel]; P5.SAssign[countLex.lexsei]; P5U.Out0[FOpCodes.qPUSH]; P5U.PushLitVal[0]; P5U.OutJump[JumpG, loopLabel]}; LoadLongAddress: PUBLIC PROC [v: VarIndex] = { -- Push a LONG address for the variable -- NOTE: clobbers the VarItem IF ~P5L.LoadAddress[v] THEN P5U.Out0[FOpCodes.qLP]}; LoadLongVarAddress: PROC [var: VarIndex] = INLINE { -- Push a LONG address for the var IF P5L.InCode[var] THEN var ← P5L.OVarItem[P5L.CopyToTemp[var].var]; LoadLongAddress[var]}; LoadSystemZone: PROC = { P5U.PushLitVal[LOOPHOLE[RTSD.SD, CARDINAL] + RTSD.sSystemZone]; P5U.Out1[FOpCodes.qRD, 0]}; AddrVarToLex: PROC [var: VarIndex, nwords: CARDINAL, pushOK: BOOL ← TRUE] RETURNS [Lexeme] = { CopyLoad[var]; RETURN [P5L.TOSAddrLex[nwords, TRUE]]}; DoubleIncr: PROC [var: VarIndex, n: CARDINAL] = { -- load the LONG variable and increment it by n -- NOTE: does not clobber the var P5L.LoadVar[P5L.CopyVarItem[var]]; P5L.GenAdd[n, TRUE]}; CopyLoad: PROC [var: VarIndex] = { -- load the variable -- NOTE: does not clobber the var P5L.LoadVar[P5L.CopyVarItem[var]]}; StackTemp: PROC [nwords: CARDINAL] RETURNS [VarIndex] = { -- make a new temporary from the top nwords of the stack RETURN [P5L.OVarItem[Stack.TempStore[nwords]]]}; StackVar: PROC [var: VarIndex, nWords: CARDINAL] RETURNS [BOOL] = { RETURN [WITH cc: cb[var] SELECT FROM o => WITH vv: cc.var SELECT FROM stack => (vv.wd = 0 AND vv.wSize = nWords), ENDCASE => FALSE, ENDCASE => FALSE]}; }.