-- VarUtils.mesa -- last edited by Sweet, 25-Aug-82 11:34:21 -- last edited by Satterthwaite, December 16, 1982 10:35 am DIRECTORY Alloc: TYPE USING [Notifier], BcdDefs: TYPE USING [Link], Code: TYPE USING [catchcount, curctxlvl, firstTemp, tempcontext], CodeDefs: TYPE USING [ Base, BdoVarIndex, BoVarIndex, BYTE, codeType, DataStackIndex, IndVarIndex, Lexeme, MoveDirection, OVarIndex, StackBackup, StackIndex, StackLocRec, TempAddr, VarComponent, VarIndex, VarItem, VarNull, VarTag, wordlength], Inline: TYPE USING [BITAND, BITSHIFT], LiteralOps: TYPE USING [MasterString, Value], Literals: TYPE USING [Base, LTNull, MSTIndex, stType], P5: TYPE USING [CreateTempLex, GenAnonLex, GenTempLex, ReleaseTempLex], P5L: TYPE USING [ AddrComponent, LoadAddress, LoadComponent, LoadVar, MakeBo, MakeComponent, StoreComponent, VarVarAssign, Words], P5U: TYPE USING [FreeChunk, GetChunk], PrincOps: TYPE USING [EPRange, GFTNull], Stack: TYPE USING [ Above, DataIndex, Forget, KeepOnly, Load, Loc, MoveToTemp, Pop, TempStore, Top], SymbolOps: TYPE USING [XferMode], Symbols: TYPE USING [ Base, BitAddress, bodyType, BTNull, CBTIndex, ContextLevel, ctxType, ISEIndex, ISENull, lG, lZ, RecordSEIndex, seType]; VarUtils: PROGRAM IMPORTS CPtr: Code, Inline, LiteralOps, P5, P5U, P5L, Stack, SymbolOps EXPORTS P5L, CodeDefs = BEGIN OPEN CodeDefs, Symbols; cb: CodeDefs.Base; seb, ctxb, bb: Symbols.Base; stb: Literals.Base; VarUtilsNotify: PUBLIC Alloc.Notifier = BEGIN -- called by allocator whenever table area is repacked seb ← base[Symbols.seType]; ctxb ← base[Symbols.ctxType]; cb ← base[codeType]; bb ← base[Symbols.bodyType]; stb ← base[Literals.stType]; END; AdjustComponent: PUBLIC PROC [var: POINTER TO VarComponent, rSei: Symbols.RecordSEIndex, fSei: Symbols.ISEIndex, tBits: CARDINAL] = BEGIN length: CARDINAL = seb[rSei].length; first: BOOL = (seb[fSei].idValue = 0); delta: CARDINAL; IF length < wordlength AND (delta ← tBits - length) # 0 THEN BEGIN IF first THEN BEGIN newB: CARDINAL = var.bSize + delta; var.bSize ← newB MOD wordlength; var.wSize ← newB / wordlength; END ELSE ModComponent[var: var, bd: delta]; END; END; AllLoaded: PUBLIC PROC [r: VarIndex, junkOk: BOOL←FALSE] RETURNS [BOOL] = BEGIN -- is completely on stack (there may be stuff above it, tho) WITH cb[r] SELECT FROM o => WITH vv: var SELECT FROM stack => IF (junkOk OR vv.wd = 0) AND vv.bd = 0 AND vv.bSize = 0 THEN BEGIN sti: StackIndex = IF vv.wd # 0 THEN Stack.Above[vv.sti, vv.wd] ELSE vv.sti; loc: StackLocRec = Stack.Loc[sti, var.wSize]; IF loc.tag = onStack THEN RETURN [TRUE]; END; ENDCASE; ENDCASE; RETURN [FALSE] END; ComponentForLex: PUBLIC PROC [l: Lexeme, allowFields: BOOL←FALSE] RETURNS [VarComponent] = BEGIN WITH ll: l SELECT FROM bdo => RETURN [P5L.MakeComponent[ll.lexbdoi, allowFields]]; se => RETURN [ComponentForSE[ll.lexsei]]; literal => BEGIN OPEN Literals; WITH ll SELECT FROM word => RETURN [[wSize: 1, space: const[d1: LiteralOps.Value[lexlti]]]]; string => BEGIN msti: MSTIndex = LiteralOps.MasterString[lexsti]; RETURN [WITH s: stb[lexsti] SELECT FROM heap => [wSize: 2, space: frame[wd: s.info, level: lG, immutable:TRUE]], ENDCASE => [wSize: 1, space: faddr[ wd: stb[msti].info, level: IF stb[msti].local THEN CPtr.curctxlvl - CPtr.catchcount ELSE lG]]]; END; ENDCASE; END; stack => RETURN [[wSize: 1, space: stack[sti: ll.lexsti]]]; ENDCASE; ERROR END; ComponentForSE: PUBLIC PROC [sei: ISEIndex] RETURNS [var: VarComponent] = BEGIN SELECT TRUE FROM sei = ISENull => ERROR; seb[sei].linkSpace => BEGIN a: BitAddress = seb[sei].idValue; var ← [wSize: 1, space: link[wd: a.wd]]; END; seb[sei].constant => SELECT SymbolOps.XferMode[seb[sei].idType] FROM proc => BEGIN bti: CBTIndex = seb[sei].idInfo; IF bti = BTNull THEN RETURN [[wSize: 1, space: const[d1: seb[sei].idValue]]] ELSE WITH bb[bti] SELECT FROM Inner => RETURN [[wSize: 1, space: faddr[wd: frameOffset, level: bb[bti].level - 1]]]; Outer => RETURN [[wSize: 1, space: pdesc[entryIndex]]]; ENDCASE; END; signal, error => BEGIN lnk: BcdDefs.Link = seb[sei].idValue; IF lnk.gfi # PrincOps.GFTNull THEN RETURN [[wSize: 1, space: pdesc[(lnk.gfi-1)*PrincOps.EPRange + lnk.ep]]] ELSE RETURN [[wSize: 1, space: const[d1: lnk]]]; END; program => BEGIN lnk: BcdDefs.Link = seb[sei].idValue; IF lnk.gfi = 1 AND lnk.ep = 0 THEN RETURN [[wSize: 1, space: faddr[wd: 0, level: lG]]]; ERROR END; ENDCASE => ERROR; ENDCASE => BEGIN a: Symbols.BitAddress = seb[sei].idValue; s: CARDINAL = seb[sei].idInfo; RETURN [[wSize: s / wordlength, bSize: s MOD wordlength, space: frame[ wd: a.wd, bd: a.bd, immutable: seb[sei].immutable, level: ctxb[seb[sei].idCtx].level]]] END; END; CopyLex: PUBLIC PROC [l: Lexeme] RETURNS [Lexeme] = BEGIN RETURN [WITH l SELECT FROM bdo => [bdo[CopyVarItem[lexbdoi]]], ENDCASE => l] END; CopyToTemp: PUBLIC PROC [r: VarIndex, tsei: ISEIndex ← ISENull] RETURNS [var: VarComponent, sei: ISEIndex] = BEGIN -- needs work for non aligned things -- tsei, if # ISENull, is an available temp of the right size bd, bSize: [0..wordlength); wSize, wS: CARDINAL; rr: VarIndex; sei ← tsei; [bd: bd, bSize: bSize, wSize: wSize] ← VarAlignment[r, load]; wS ← P5L.Words[wSize, bSize]; WITH cc: cb[r] SELECT FROM o => WITH vv: cc.var SELECT FROM stack => IF vv.bd = 0 AND vv.bSize = 0 THEN BEGIN junk: CARDINAL ← vv.wd; originalFirst: StackIndex = vv.sti; sti: StackIndex ← Stack.Above[vv.sti, junk]; IF sei = ISENull THEN -- can store anywhere BEGIN var ← Stack.MoveToTemp[firstIndex: sti, count: wS, preChaff: junk]; WITH vv1: var SELECT FROM frame => BEGIN tlex: Lexeme.se; IF vv1.level # ctxb[CPtr.tempcontext].level THEN GO TO move; tlex ← P5.CreateTempLex[wdoffset: vv1.wd, nwords: wS]; sei ← tlex.lexsei; IF vv1.wd >= CPtr.firstTemp THEN -- not somebody's immutable P5.ReleaseTempLex[tlex]; -- will be freed after stmt END; ENDCASE => GO TO move; EXITS move => BEGIN tlex: Lexeme.se = P5.GenTempLex[wS]; sei ← tlex.lexsei; [] ← P5L.VarVarAssign[ to: VarForLex[tlex], from: OVarItem[var], isexp: FALSE]; var ← ComponentForSE[sei]; END; END ELSE BEGIN tvar: VarComponent; var ← ComponentForSE[sei]; FOR i: CARDINAL DECREASING IN [0..wS) DO Stack.Load[Stack.Above[sti, i]]; tvar ← var; FieldOfComponent[var: @tvar, wd: i, wSize: 1]; P5L.StoreComponent[tvar]; ENDLOOP; IF junk # 0 THEN { Stack.Load[originalFirst, junk]; -- in case they aren't on top Stack.Pop[junk]}; END; ReleaseVarItem[r]; RETURN END; ENDCASE; ENDCASE; IF sei = ISENull THEN sei ← P5.GenTempLex[wS].lexsei; var ← ComponentForSE[sei]; IF wS > 1 THEN BEGIN var.wSize ← wSize; var.bSize ← bSize; WITH vv: var SELECT FROM frame => vv.bd ← bd; ENDCASE; END; rr ← OVarItem[var]; [] ← P5L.VarVarAssign[rr, r, FALSE]; RETURN END; CopyVarItem: PUBLIC PROC [r: VarIndex] RETURNS [rr: VarIndex] = BEGIN -- LOOPHOLEs can go away when the compiler gets smarter WITH cc: cb[r] SELECT FROM o => BEGIN tr: OVarIndex = LOOPHOLE[GenVarItem[o]]; rr ← tr; cb[tr] ← cc; END; bo => BEGIN tr: BoVarIndex = LOOPHOLE[GenVarItem[bo]]; rr ← tr; cb[tr] ← cc; END; bdo => BEGIN tr: BdoVarIndex = LOOPHOLE[GenVarItem[bdo]]; rr ← tr; cb[tr] ← cc; END; ind => BEGIN tr: IndVarIndex = LOOPHOLE[GenVarItem[ind]]; rr ← tr; cb[tr] ← cc; END; ENDCASE => ERROR; RETURN END; EasilyLoadable: PUBLIC PROC [var: VarComponent, dir: MoveDirection] RETURNS [evar: VarComponent] = BEGIN -- dir = store means it could be clobbered between loads size: CARDINAL = P5L.Words[var.wSize, var.bSize]; -- < 3 IF EasyToLoad[var, dir] THEN RETURN [var]; WITH vv: var SELECT FROM stack => IF vv.wd = 0 THEN BEGIN loc: StackLocRec = Stack.Loc[vv.sti, size]; WITH loc SELECT FROM contig => WITH bb: place SELECT FROM frame => BEGIN tvar: VarComponent = [wSize: vv.wSize, bSize: vv.bSize, space: frame[immutable: TRUE, level: bb.tLevel, wd: bb.tOffset, bd: vv.bd]]; Stack.Forget[vv.sti, size]; RETURN [EasilyLoadable[tvar, dir]]; END; link => BEGIN tvar: VarComponent = [wSize: 1, space: link[wd: bb.link]]; Stack.Forget[vv.sti, 1]; RETURN [tvar]; END; ENDCASE; ENDCASE; END; ENDCASE; P5L.LoadComponent[var]; RETURN [Stack.TempStore[size]] END; EasyToLoad: PUBLIC PROC [var: VarComponent, dir: MoveDirection] RETURNS [BOOL] = BEGIN -- dir = store means it could be clobbered between loads lvl: ContextLevel; WITH vv: var SELECT FROM const, link, linkup, caddr, code => RETURN [TRUE]; faddr => lvl ← vv.level; frame => BEGIN IF vv.bd # 0 OR var.bSize # 0 OR var.wSize NOT IN [1..2] OR (dir = store AND ~vv.immutable) THEN RETURN [FALSE]; lvl ← vv.level; END; frameup => BEGIN IF dir = store AND ~vv.immutable THEN RETURN [FALSE]; lvl ← vv.level; END; ENDCASE => RETURN [FALSE]; SELECT lvl FROM lZ => ERROR; lG, CPtr.curctxlvl => RETURN [TRUE]; ENDCASE => RETURN [FALSE]; END; FieldOfComponent: PUBLIC PROC [var: POINTER TO VarComponent, wd, bd, wSize, bSize: CARDINAL ← 0] = BEGIN ModComponent[var, wd, bd]; IF wSize = 0 THEN WITH vv: var↑ SELECT FROM const => BEGIN OPEN Inline; Mask: ARRAY [0..15] OF CARDINAL = [ 0b, 1b, 3b, 7b, 17b, 37b, 77b, 177b, 377b, 777b, 1777b, 3777b, 7777b, 17777b, 37777b, 77777b]; vv.d1 ← BITAND[BITSHIFT[vv.d1, vv.bd+bSize-wordlength], Mask[bSize]]; wSize ← 1; bSize ← 0; END; ENDCASE; var.wSize ← wSize; var.bSize ← bSize; END; FieldOfComponentOnly: PUBLIC PROC [var: POINTER TO VarComponent, wd, bd, wSize, bSize: CARDINAL ← 0] = BEGIN WITH vv: var↑ SELECT FROM stack => BEGIN -- throw away anything above this new field b: CARDINAL = vv.bd + bd; ws: CARDINAL = P5L.Words[wSize, bSize]; vv.wd ← vv.wd + wd + b/wordlength; vv.bd ← b MOD wordlength; Stack.KeepOnly[Stack.Above[vv.sti, vv.wd], ws]; var.wSize ← wSize; var.bSize ← bSize; END; ENDCASE => FieldOfComponent[var, wd, bd, wSize, bSize]; END; FieldOfVar: PUBLIC PROC [r: VarIndex, wd, bd, wSize, bSize: CARDINAL ← 0] = BEGIN ModField: PROC [var: LONG POINTER TO VarComponent] = BEGIN -- had better not cause a compaction b: CARDINAL; WITH vv: var↑ SELECT FROM frame => BEGIN IF vv.level # lZ THEN ERROR; b ← vv.bd + bd; vv.wd ← vv.wd + wd + b/wordlength; vv.bd ← b MOD wordlength; END; code => BEGIN vv.lti ← Literals.LTNull; b ← vv.bd + bd; vv.wd ← vv.wd + wd + b/wordlength; vv.bd ← b MOD wordlength; END; ENDCASE => ERROR; var.wSize ← wSize; var.bSize ← bSize; END; WITH cb[r] SELECT FROM o => BEGIN vComp: VarComponent ← var; FieldOfComponent[@vComp, wd, bd, wSize, bSize]; var ← vComp; END; bo => ModField[@offset]; bdo => ModField[@offset]; ind => ModField[@offset]; ENDCASE; END; FieldOfVarOnly: PUBLIC PROC [r: VarIndex, wd, bd, wSize, bSize: CARDINAL ← 0] = BEGIN WITH cb[r] SELECT FROM o => BEGIN vComp: VarComponent ← var; FieldOfComponentOnly[@vComp, wd, bd, wSize, bSize]; var ← vComp; END; ENDCASE => FieldOfVar[r, wd, bd, wSize, bSize]; END; varCount, varMax: CARDINAL ← 0; GenVarItem: PUBLIC PROC [tag: VarTag] RETURNS [r: VarIndex] = BEGIN -- returns the cb-relative index of a VarItem varCount ← varCount + 1; varMax ← MAX[varMax, varCount]; r ← P5U.GetChunk[(SELECT tag FROM o => VarItem.o.SIZE, bo => VarItem.bo.SIZE, bdo => VarItem.bdo.SIZE, ind => VarItem.ind.SIZE, ENDCASE => ERROR)]; RETURN END; InCode: PUBLIC PROC [r: VarIndex] RETURNS [BOOL] = BEGIN RETURN [WITH cb[r] SELECT FROM o => var.tag = code, bo => offset.tag = code, bdo => offset.tag = code, ind => offset.tag = code, ENDCASE => ERROR] END; IsCopyKnown: PUBLIC PROC [var: VarComponent] RETURNS [known: BOOL, cvar: VarComponent] = BEGIN wS: CARDINAL = P5L.Words[var.wSize, var.bSize]; WITH vv: var SELECT FROM stack => BEGIN sti: DataStackIndex ← Stack.DataIndex[Stack.Above[vv.sti, vv.wd]]; tLevel: Symbols.ContextLevel; tOffset: TempAddr; sb: StackBackup ← cb[sti].backup; WITH bb: sb SELECT FROM link => IF wS = 1 THEN RETURN [TRUE, [wSize: 1, space: link[wd: bb.link]]] ELSE GO TO nope; frame => {tLevel ← bb.tLevel; tOffset ← bb.tOffset}; const => IF vv.bSize = 0 AND vv.bd = 0 THEN SELECT wS FROM 1 => RETURN [TRUE, [wSize: 1, space: const[d1: bb.value]]]; 2 => BEGIN nsti: DataStackIndex = Stack.DataIndex[Stack.Above[sti]]; WITH bb2: cb[nsti].backup SELECT FROM const => RETURN[ TRUE, [wSize: 1, space: const[d1: bb.value, d2: bb2.value]]]; ENDCASE => GO TO nope; END; ENDCASE => GO TO nope; ENDCASE => GO TO nope; FOR i: CARDINAL IN (0..wS) DO sti ← Stack.DataIndex[Stack.Above[sti]]; sb ← cb[sti].backup; WITH bb: sb SELECT FROM frame => IF bb.tLevel # tLevel OR bb.tOffset # tOffset+i THEN GO TO nope; ENDCASE => GO TO nope; REPEAT FINISHED => RETURN [ TRUE, [wSize: var.wSize, bSize: var.bSize, space: frame[wd: tOffset, level: tLevel, bd: vv.bd]]]; ENDLOOP; END; ENDCASE => GO TO nope; EXITS nope => RETURN [FALSE, [space: frame[]]] END; LongVarAddress: PUBLIC PROC [r: VarIndex] RETURNS [BOOL] = BEGIN RETURN [WITH cb[r] SELECT FROM o => FALSE, bo => P5L.Words[base.wSize, base.bSize] > 1, bdo => P5L.Words[disp.wSize, disp.bSize] > 1 OR P5L.Words[base.wSize, base.bSize] > 1, ind => P5L.Words[base.wSize, base.bSize] > 1, ENDCASE => ERROR] END; ModComponent: PUBLIC PROC [var: POINTER TO VarComponent, wd, bd: CARDINAL ← 0] = BEGIN b: CARDINAL; WITH vv: var↑ SELECT FROM stack => BEGIN nsti: StackIndex; dwd: CARDINAL; b ← vv.bd + bd; dwd ← wd + b/wordlength; IF dwd # 0 THEN BEGIN nsti ← Stack.Above[vv.sti, vv.wd + dwd]; vv.sti ← nsti; vv.wd ← 0; END; vv.bd ← b MOD wordlength; END; frame => BEGIN b ← vv.bd + bd; vv.wd ← vv.wd + wd + b/wordlength; vv.bd ← b MOD wordlength; END; code => BEGIN vv.lti ← Literals.LTNull; b ← vv.bd + bd; vv.wd ← vv.wd + wd + b/wordlength; vv.bd ← b MOD wordlength; END; const => BEGIN b ← vv.bd + bd; SELECT wd + b/wordlength FROM 0 => NULL; 1 => vv.d1 ← vv.d2; ENDCASE => ERROR; vv.bd ← b MOD wordlength; END; ENDCASE => ERROR; END; NormalizeExp: PUBLIC PROC [ r: VarIndex, tempsei: ISEIndex ← ISENull, codeOk: BOOL ← FALSE] RETURNS [nwords: CARDINAL, long: BOOL, tsei: ISEIndex] = BEGIN wSize: CARDINAL; bSize: [0..wordlength); tsei ← tempsei; [wSize: wSize, bSize: bSize] ← VarAlignment[r, load]; nwords ← P5L.Words[wSize, bSize]; IF nwords <= 2 THEN {P5L.LoadVar[r]; long ← FALSE} ELSE IF codeOk OR ~InCode[r] THEN long ← P5L.LoadAddress[r, codeOk] ELSE BEGIN tvar: VarComponent; IF tsei = ISENull THEN tsei ← P5.GenAnonLex[nwords].lexsei; [var: tvar, sei: tsei] ← CopyToTemp[r, tsei]; P5L.LoadComponent[P5L.AddrComponent[tvar]]; long ← FALSE; END; RETURN END; NormalLex: PUBLIC PROC [nwords: CARDINAL, long, code: BOOL←FALSE] RETURNS [Lexeme] = BEGIN RETURN [SELECT TRUE FROM (nwords <= 2) => TOSLex[nwords], code => TOSCodeAddrLex[nwords], ENDCASE => TOSAddrLex[nwords, long]] END; OVarItem: PUBLIC PROC [var: VarComponent] RETURNS [r: VarIndex] = BEGIN r ← GenVarItem[o]; cb[r] ← [body: o[var: var]]; RETURN END; ReleaseLex: PUBLIC PROC [lex: Lexeme] = BEGIN WITH lex SELECT FROM bdo => ReleaseVarItem[lexbdoi]; ENDCASE; END; PFSize: CARDINAL = 4; pendingFree: ARRAY [0..PFSize) OF VarIndex ← ALL[VarNull]; pfFirst, pfLast: CARDINAL ← 0; pfDebug: PUBLIC BOOL ← FALSE; BadRelease: PUBLIC SIGNAL [badr: VarIndex] = CODE; ReleaseVarItem: PUBLIC PROC [r: VarIndex] = BEGIN IF r = VarNull OR cb[r].free THEN GO TO bad; IF ~pfDebug THEN ReleaseReally[r] ELSE BEGIN FOR i: CARDINAL IN [0..PFSize) DO IF pendingFree[i] = r THEN GO TO bad; ENDLOOP; pfLast ← (pfLast+1) MOD PFSize; IF pfLast = pfFirst THEN BEGIN ReleaseReally[pendingFree[pfFirst]]; pfFirst ← (pfFirst+1) MOD PFSize; END; pendingFree[pfLast] ← r; END; EXITS bad => SIGNAL BadRelease[r]; END; ReleaseReally: PROC [r: VarIndex] = BEGIN IF r = VarNull THEN RETURN; varCount ← varCount - 1; P5U.FreeChunk[r, (WITH cb[r] SELECT FROM o => VarItem.o.SIZE, bo => VarItem.bo.SIZE, bdo => VarItem.bdo.SIZE, ind => VarItem.ind.SIZE, ENDCASE => ERROR)]; END; ReusableCopies: PUBLIC PROC [ r: VarIndex, dir: MoveDirection, stackOk: BOOL, stackFree: BOOL←FALSE] RETURNS [first, next: VarIndex] = BEGIN -- make sure r has reusable pointer parts first ← r; -- in case it's already reusable BEGIN -- to set up "doBo" exit WITH cc: cb[r] SELECT FROM o => IF ~stackOk THEN WITH cc.var SELECT FROM stack => BEGIN knownCopy: BOOL; cvar: VarComponent; IF stackFree THEN GO TO storIt; [knownCopy, cvar] ← IsCopyKnown[cc.var]; IF ~knownCopy THEN GO TO storIt; next ← OVarItem[cvar]; RETURN EXITS storIt => BEGIN tvar: VarComponent = CopyToTemp[r].var; first ← OVarItem[tvar]; END; END; frameup => IF ~immutable THEN GO TO doBo; ENDCASE; bo => WITH cc.base SELECT FROM stack => BEGIN knownCopy: BOOL; cvar: VarComponent; IF stackFree THEN GO TO doBo; [knownCopy, cvar] ← IsCopyKnown[cc.base]; IF ~knownCopy THEN GO TO doBo; next ← GenVarItem[bo]; cb[next] ← [body: bo[base: cvar, offset: cc.offset]]; RETURN END; ENDCASE => GO TO doBo; ind => IF cc.packtag = packed THEN BEGIN cc.base ← EasilyLoadable[cc.base, dir]; cc.index ← EasilyLoadable[cc.index, dir]; END ELSE GO TO doBo; ENDCASE => GO TO doBo; EXITS doBo => BEGIN bor: BoVarIndex = P5L.MakeBo[r]; cb[bor].base ← EasilyLoadable[cb[bor].base, dir]; first ← bor; END; END; next ← CopyVarItem[first]; RETURN END; StackSpareAddr: PUBLIC PROC [r: VarIndex] RETURNS [BOOL] = BEGIN -- no excess stack depth required to load address of r WITH cc: cb[r] SELECT FROM o => RETURN [WITH vv: cc.var SELECT FROM code => TRUE, linkup => vv.delta = 0, frameup => vv.delta = 0, frame => vv.wd IN BYTE, ENDCASE => FALSE]; bo => BEGIN opFree: BOOL; br: VarIndex; WITH oo: cc.offset SELECT FROM frame => IF oo.wd # 0 THEN RETURN [FALSE]; code => IF oo.wd # 0 THEN RETURN [FALSE]; ENDCASE; br ← OVarItem[cc.base]; opFree ← StackSpareLoad[br]; ReleaseVarItem[br]; RETURN [opFree] END; ENDCASE => RETURN [FALSE]; END; StackSpareLoad: PUBLIC PROC [r: VarIndex] RETURNS [BOOL] = BEGIN -- no excess stack depth required to load r WITH cc: cb[r] SELECT FROM o => RETURN [WITH vv: cc.var SELECT FROM code, caddr, const, pdesc, linkup, frameup => TRUE, frame => vv.wd IN BYTE, faddr => vv.wd IN BYTE, stack => vv.wd = 0 AND vv.bd = 0 AND vv.bSize = 0, const => TRUE, ENDCASE => FALSE]; bo => BEGIN br: VarIndex; opFree: BOOL; WITH oo: cc.offset SELECT FROM frame => IF oo.wd NOT IN BYTE THEN RETURN [FALSE]; code => IF oo.wd NOT IN BYTE THEN RETURN [FALSE]; ENDCASE; br ← OVarItem[cc.base]; opFree ← StackSpareLoad[br]; ReleaseVarItem[br]; RETURN [opFree] END; ENDCASE => RETURN [FALSE]; END; TOSAddrLex: PUBLIC PROC [size: CARDINAL, long: BOOL←FALSE] RETURNS [Lexeme.bdo] = BEGIN r: VarIndex = GenVarItem[bo]; base: VarComponent = TOSComponent[IF long THEN 2 ELSE 1]; IF size = 0 THEN ERROR; cb[r] ← [body: bo[base: base, offset: [wSize: size, space: frame[]]]]; RETURN [[bdo[r]]] END; TOSCodeAddrLex: PUBLIC PROC [size: CARDINAL] RETURNS [Lexeme.bdo] = BEGIN r: VarIndex = GenVarItem[bo]; base: VarComponent = TOSComponent[1]; IF size = 0 THEN ERROR; cb[r] ← [body: bo[base: base, offset: [wSize: size, space: code[]]]]; RETURN [[bdo[r]]] END; TOSComponent: PUBLIC PROC [size: CARDINAL ← 1] RETURNS [VarComponent] = BEGIN IF size = 0 THEN ERROR; RETURN [[wSize: size, space: stack[sti: Stack.Top[size]]]] END; TOSLex: PUBLIC PROC [size: CARDINAL ← 1] RETURNS [Lexeme] = BEGIN r: VarIndex; SELECT size FROM 0 => ERROR; 1 => RETURN [[stack[Stack.Top[]]]]; ENDCASE; r ← GenVarItem[o]; cb[r] ← [body: o[var: [wSize: size, space: stack[sti: Stack.Top[size]]]]]; RETURN [[bdo[r]]] END; VarAddressEasy: PUBLIC PROC [r: VarIndex] RETURNS [BOOL] = BEGIN WITH cc: cb[r] SELECT FROM o => RETURN [WITH vv: cc.var SELECT FROM code => TRUE, linkup => vv.delta = 0, frame => vv.level = lG OR vv.level = CPtr.curctxlvl, frameup => vv.delta = 0 AND (vv.level = lG OR vv.level = CPtr.curctxlvl), ENDCASE => FALSE]; bo => WITH oo: cc.offset SELECT FROM frame => IF oo.wd = 0 AND oo.level = lZ THEN RETURN [EasyToLoad[cc.base, store]]; code => IF oo.wd = 0 THEN RETURN [EasyToLoad[cc.base, store]]; ENDCASE; ENDCASE; RETURN [FALSE] END; VarAlignment: PUBLIC PROC [r: VarIndex, dir: MoveDirection] RETURNS [bd, bSize: [0..wordlength), wSize: CARDINAL] = BEGIN WITH cc: cb[r] SELECT FROM o => BEGIN WITH vv: cc.var SELECT FROM frame => bd ← vv.bd; code => {IF dir = store THEN ERROR; bd ← vv.bd}; stack => {IF dir = store THEN ERROR; bd ← vv.bd}; const => {IF dir = store THEN ERROR; bd ← vv.bd}; ENDCASE => {IF dir = store THEN ERROR; bd ← 0}; wSize ← cc.var.wSize; bSize ← cc.var.bSize; END; bo => BEGIN WITH oo: cc.offset SELECT FROM frame => bd ← oo.bd; code => {IF dir = store THEN ERROR; bd ← oo.bd}; ENDCASE => ERROR; wSize ← cc.offset.wSize; bSize ← cc.offset.bSize; END; bdo => BEGIN WITH oo: cc.offset SELECT FROM frame => bd ← oo.bd; code => {IF dir = store THEN ERROR; bd ← oo.bd}; ENDCASE => ERROR; wSize ← cc.offset.wSize; bSize ← cc.offset.bSize; END; ind => BEGIN WITH oo: cc.offset SELECT FROM frame => bd ← oo.bd; code => {IF dir = store THEN ERROR; bd ← oo.bd}; ENDCASE => ERROR; wSize ← cc.offset.wSize; bSize ← cc.offset.bSize; END; ENDCASE => ERROR; RETURN END; VarFinal: PUBLIC PROC = BEGIN pendingFree ← ALL[VarNull]; -- don't bother to free, tables reset next END; VarForLex: PUBLIC PROC [l: Lexeme] RETURNS [r: VarIndex] = BEGIN var: VarComponent; WITH ll: l SELECT FROM bdo => RETURN [ll.lexbdoi]; ENDCASE => var ← ComponentForLex[l]; r ← GenVarItem[o]; cb[r] ← [body: o[var: var]]; END; VarStackWords: PUBLIC PROC [r: VarIndex] RETURNS [nW: CARDINAL] = BEGIN -- number of words on the virtual stack nW ← 0; WITH cb[r] SELECT FROM o => WITH vv: var SELECT FROM stack => nW ← nW + P5L.Words[vv.wSize, vv.bSize]; ENDCASE; bo => WITH vv: base SELECT FROM stack => nW ← nW + P5L.Words[vv.wSize, vv.bSize]; ENDCASE; bdo => BEGIN WITH vv: base SELECT FROM stack => nW ← nW + P5L.Words[vv.wSize, vv.bSize]; ENDCASE; WITH vv: disp SELECT FROM stack => nW ← nW + P5L.Words[vv.wSize, vv.bSize]; ENDCASE; END; ind => BEGIN WITH vv: base SELECT FROM stack => nW ← nW + P5L.Words[vv.wSize, vv.bSize]; ENDCASE; WITH vv: index SELECT FROM stack => nW ← nW + P5L.Words[vv.wSize, vv.bSize]; ENDCASE; END; ENDCASE; RETURN END; END.