-- Calls.mesa -- last modified by Sweet, September 18, 1980 2:56 PM -- last modified by Satterthwaite, March 21, 1983 9:33 am DIRECTORY Alloc: TYPE USING [Notifier], Code: TYPE USING [ actenable, catchcount, cfsi, cfSize, CodePassInconsistency, codeptr, substenable], CodeDefs: TYPE USING [ Base, BoVarIndex, Byte, CodeCCIndex, codeType, LabelCCIndex, LabelCCNull, Lexeme, MaxParmsInStack, NullLex, VarComponent, VarIndex], ComData: TYPE USING [bodyIndex, stopping, switches], Counting: TYPE USING [CheckArgRefs, Free], Environment: TYPE USING [bitsPerWord], FOpCodes: TYPE USING [ qALLOC, qBLT, qCATCH, qDUP, qEFC, qFREE, qGADRB, qKFCB, qLFC, qLI, qLL, qLP, qMRE, qMREL, qMXD, qMXDL, qMXW, qMXWL, qPORTI, qPORTO, qPUSH, qR, qRDL, qRL, qSFC], Log: TYPE USING [Error, Warning], OpTableDefs: TYPE USING [InstLength], P5: TYPE USING [ CatchPhrase, Exp, GenTempLex, PushLex, PushRhs, ReleaseLock, SAssign, SCatchPhrase, TransferConstruct], P5L: TYPE USING [ CopyToTemp, CopyVarItem, EasilyLoadable, GenVarItem, LoadAddress, LoadComponent, LoadVar, MakeBo, OVarItem, ReusableCopies, TOSAddrLex, TOSLex, ReleaseLex, VarForLex, VarVarAssign], P5S: TYPE USING [], P5U: TYPE USING [ AllocCodeCCItem, BitsForOperand, BitsForType, ComputeFrameSize, CreateLabel, InsertLabel, LabelAlloc, LongTreeAddress, NextVar, OperandType, Out0, Out1, OutJump, PushLitVal, TreeLiteralValue, WordsForOperand, WordsForSei], PrincOps: TYPE USING [AllocationVectorSize, returnOffset], RTSD: TYPE USING [sFork, sProcCheck], SDDefs: TYPE USING [ sCopy, sError, sErrorList, sFork, sJoin, sRestart, sReturnError, sReturnErrorList, sSignal, sSignalList, sStart, sUnnamedError], Stack: TYPE USING [DeleteToMark, Dump, Incr, Load, Mark, TempStore, Top], SymbolOps: TYPE USING [ FindExtension, FirstCtxSe, NextSe, TransferTypes, WordsForType, XferMode], Symbols: TYPE USING [ Base, BitAddress, bodyType, CBTIndex, CBTNull, ContextLevel, CSEIndex, CTXIndex, ctxType, ISEIndex, lG, RecordSEIndex, SEIndex, SENull, seType], Tree: TYPE USING [Base, Index, Link, Null, treeType], TreeOps: TYPE USING [FreeNode, GetNode, OpName, NthSon, ScanList, UpdateList]; Calls: PROGRAM IMPORTS MPtr: ComData, CPtr: Code, Counting, Log, OpTableDefs, P5, P5L, P5U, Stack, SymbolOps, TreeOps EXPORTS CodeDefs, P5, P5S = BEGIN OPEN CodeDefs; -- imported definitions bitsPerWord: CARDINAL = Environment.bitsPerWord; BitAddress: TYPE = Symbols.BitAddress; CBTIndex: TYPE = Symbols.CBTIndex; CBTNull: CBTIndex = Symbols.CBTNull; ContextLevel: TYPE = Symbols.ContextLevel; CSEIndex: TYPE = Symbols.CSEIndex; CTXIndex: TYPE = Symbols.CTXIndex; ISEIndex: TYPE = Symbols.ISEIndex; lG: ContextLevel = Symbols.lG; RecordSEIndex: TYPE = Symbols.RecordSEIndex; tb: Tree.Base; -- tree base (local copy) seb: Symbols.Base; -- semantic entry base (local copy) ctxb: Symbols.Base; -- context entry base (local copy) bb: Symbols.Base; -- body entry base (local copy) cb: CodeDefs.Base; -- code base (local copy) CallsNotify: PUBLIC Alloc.Notifier = BEGIN -- called by allocator whenever table area is repacked seb ← base[Symbols.seType]; ctxb ← base[Symbols.ctxType]; bb ← base[Symbols.bodyType]; tb ← base[Tree.treeType]; cb ← base[codeType]; END; SysError: PUBLIC PROC = BEGIN Stack.Dump[]; Stack.Mark[]; SysCall[SDDefs.sUnnamedError]; CallCatch[Tree.Null]; P5U.OutJump[JumpRet,LabelCCNull]; END; SysErrExp: PUBLIC PROC [node: Tree.Index] RETURNS [Lexeme] = BEGIN nrets: CARDINAL = P5U.WordsForSei[tb[node].info]; Stack.Dump[]; Stack.Mark[]; SysCall[SDDefs.sUnnamedError]; CallCatch[Tree.Null]; P5U.OutJump[JumpRet,LabelCCNull]; RETURN [PRetLex[nrets, node, TRUE]] END; Create: PUBLIC PROC [node: Tree.Index] RETURNS [Lexeme] = BEGIN -- generate code for NEW Stack.Dump[]; Stack.Mark[]; IF tb[node].attr1 THEN P5.PushRhs[tb[node].son[1]] ELSE P5U.Out1[FOpCodes.qGADRB, 0]; SysCall[SDDefs.sCopy]; CallCatch[IF tb[node].nSons > 2 THEN tb[node].son[3] ELSE Tree.Null]; Stack.Incr[1]; RETURN [P5L.TOSLex[1]] END; SStart: PROC [node: Tree.Index] RETURNS [nrets: CARDINAL] = BEGIN ptsei: CSEIndex = P5U.OperandType[tb[node].son[1]]; Stack.Dump[]; Stack.Mark[]; [] ← PushParms[tb[node].attr1, tb[node].son[2], ptsei, FALSE]; P5.PushRhs[tb[node].son[1]]; SysCall[SDDefs.sStart]; CallCatch[IF tb[node].nSons > 2 THEN tb[node].son[3] ELSE Tree.Null]; RETURN [P5U.WordsForSei[SymbolOps.TransferTypes[ptsei].typeOut]] END; Start: PUBLIC PROC [node: Tree.Index] = {[] ← SStart[node]}; StartExp: PUBLIC PROC [node: Tree.Index] RETURNS [Lexeme] = BEGIN nrets: CARDINAL = SStart[node]; RETURN [PRetLex[nrets, node, FALSE]] END; Restart: PUBLIC PROC [node: Tree.Index] = BEGIN Stack.Dump[]; Stack.Mark[]; P5.PushRhs[tb[node].son[1]]; SysCall[SDDefs.sRestart]; CallCatch[IF tb[node].nSons > 2 THEN tb[node].son[3] ELSE Tree.Null]; END; Stop: PUBLIC PROC [node: Tree.Index] = BEGIN OPEN FOpCodes; IF ~MPtr.stopping THEN SIGNAL CPtr.CodePassInconsistency; P5U.Out1[qLL, PrincOps.returnOffset]; P5U.Out0[qSFC]; END; CallCatch: PUBLIC PROC [t: Tree.Link] = BEGIN IF t # Tree.Null THEN P5.CatchPhrase[TreeOps.GetNode[t]] ELSE ChainCatch[CPtr.actenable]; END; ChainCatch: PROC [label: LabelCCIndex] = BEGIN IF label # LabelCCNull THEN BEGIN clabel: LabelCCIndex = P5U.LabelAlloc[]; P5U.Out1[FOpCodes.qCATCH, CPtr.cfsi]; P5U.OutJump[JumpA, clabel]; P5U.OutJump[Jump, label]; P5U.InsertLabel[clabel]; END; END; SCall: PROC [node: Tree.Index] RETURNS [nrets: CARDINAL] = BEGIN -- generates code for procedure call statement OPEN FOpCodes; ptsei: CSEIndex = P5U.OperandType[tb[node].son[1]]; portcall: BOOL = (SymbolOps.XferMode[ptsei] = port); computedtarget: BOOL; nparms: CARDINAL; sei: ISEIndex; inlineCall: BOOL; WITH tb[node].son[1] SELECT FROM symbol => BEGIN sei ← index; inlineCall ← seb[sei].constant AND seb[sei].extended; computedtarget ← ctxb[seb[sei].idCtx].level # lG; END; ENDCASE => {inlineCall ← FALSE; computedtarget ← TRUE}; IF ~inlineCall THEN Stack.Dump[]; Stack.Mark[]; nparms ← PushParms[tb[node].attr1, tb[node].son[2], ptsei, FALSE, ~portcall]; IF inlineCall THEN BEGIN inlineTree: Tree.Link = SymbolOps.FindExtension[sei].tree; Stack.DeleteToMark[]; TreeOps.ScanList[TreeOps.NthSon[inlineTree, 1], CodeInline]; END ELSE IF computedtarget THEN IF portcall THEN BEGIN [] ← P5L.LoadAddress[P5L.VarForLex[P5.Exp[tb[node].son[1]]]]; Stack.DeleteToMark[]; Stack.Incr[1]; P5U.Out0[qPORTO]; P5U.Out0[qPORTI]; END ELSE BEGIN P5.PushRhs[tb[node].son[1]]; Stack.DeleteToMark[]; Stack.Incr[1]; P5U.Out0[qSFC]; END ELSE BEGIN Stack.DeleteToMark[]; -- assert that loading pdesc won't dump stack IF seb[sei].constant THEN BEGIN bti: CBTIndex = seb[sei].idInfo; IF bti # CBTNull AND bb[bti].nesting = Outer THEN P5U.Out1[qLFC, bb[bti].entryIndex] ELSE {P5.PushLex[[se[sei]]]; P5U.Out0[qSFC]}; END ELSE IF portcall THEN BEGIN [] ← P5L.LoadAddress[P5L.VarForLex[[se[sei]]]]; P5U.Out0[qPORTO]; P5U.Out0[qPORTI]; END ELSE IF seb[sei].linkSpace THEN {a: BitAddress = seb[sei].idValue; P5U.Out1[qEFC, a.wd]} ELSE {P5.PushLex[[se[sei]]]; P5U.Out0[qSFC]}; END; nrets ← P5U.WordsForSei[SymbolOps.TransferTypes[ptsei].typeOut]; IF inlineCall THEN {IF tb[node].nSons > 2 THEN P5.CatchPhrase[TreeOps.GetNode[tb[node].son[3]]]} ELSE CallCatch[IF tb[node].nSons > 2 THEN tb[node].son[3] ELSE Tree.Null]; RETURN END; ConstructOnStack: PUBLIC PROC [maint: Tree.Link, rcsei: RecordSEIndex] = BEGIN OPEN SymbolOps; ctx: CTXIndex = seb[rcsei].fieldCtx; sei: ISEIndex; firstArg: BOOL ← TRUE; DoSafen: PROC [t: Tree.Link] RETURNS [v: Tree.Link] = BEGIN SELECT TreeOps.OpName[t] FROM safen => BEGIN node: Tree.Index = TreeOps.GetNode[t]; IF firstArg OR ~tb[node].attr2 THEN BEGIN -- this dies horribly if there is only a single -- parameter, i.e., no list node, since the call node -- then contains a pointer to the safen which we free -- Therefore, we test below for safen. v ← tb[node].son[1]; tb[node].son[1] ← Tree.Null; TreeOps.FreeNode[node]; 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; v ← [symbol[sei]]; TreeOps.FreeNode[node]; END; firstArg ← FALSE; END; cast, pad => BEGIN node: Tree.Index = TreeOps.GetNode[t]; tb[node].son[1] ← DoSafen[tb[node].son[1]]; v ← t; END; ENDCASE => -- dont unroll nested constructors BEGIN v ← t; firstArg ← FALSE END; RETURN END; LoadOne: PROC [t: Tree.Link] = BEGIN IF t = Tree.Null THEN THROUGH [0..SymbolOps.WordsForType[seb[sei].idType]) DO P5U.Out1[FOpCodes.qLI, 0]; ENDLOOP ELSE IF TreeOps.OpName[t] = pad THEN BEGIN t1: Tree.Link = TreeOps.NthSon[t, 1]; delta: CARDINAL = P5U.BitsForType[seb[sei].idType] - P5U.BitsForOperand[t1]; P5.PushRhs[t1]; IF delta MOD bitsPerWord # 0 THEN ERROR; THROUGH [0.. delta/bitsPerWord) DO P5U.Out1[FOpCodes.qLI, 0] ENDLOOP; END ELSE P5.PushRhs[t]; sei ← P5U.NextVar[SymbolOps.NextSe[sei]]; END; SELECT TreeOps.OpName[maint] FROM list => BEGIN maint ← TreeOps.UpdateList[maint, DoSafen]; sei ← SymbolOps.FirstCtxSe[ctx]; TreeOps.ScanList[maint, LoadOne]; END; safen => P5.PushRhs[TreeOps.NthSon[maint, 1]]; ENDCASE => P5.PushRhs[maint]; END; SSigErr: PROC [node: Tree.Index, error: BOOL] RETURNS [nrets: CARDINAL] = BEGIN -- generates code for signal/error ptsei: CSEIndex = P5U.OperandType[tb[node].son[1]]; nparms: CARDINAL; sysFn: ARRAY BOOL OF ARRAY BOOL OF Byte = [ [SDDefs.sSignal, SDDefs.sSignalList], [SDDefs.sError, SDDefs.sErrorList]]; Stack.Dump[]; Stack.Mark[]; IF tb[node].son[1] = Tree.Null THEN P5U.PushLitVal[-1] ELSE P5.PushRhs[tb[node].son[1]]; nparms ← PushParms[tb[node].attr1, tb[node].son[2], ptsei, TRUE]; SysCall[sysFn[error][nparms > 1]]; nrets ← P5U.WordsForSei[SymbolOps.TransferTypes[ptsei].typeOut]; CallCatch[IF tb[node].nSons > 2 THEN tb[node].son[3] ELSE Tree.Null]; RETURN END; RetWithError: PUBLIC PROC [node: Tree.Index] = BEGIN -- generates code for RETURN WITH error ptsei: CSEIndex = P5U.OperandType[tb[node].son[1]]; nparms: CARDINAL; monitored: BOOL ← tb[node].attr1; IF monitored AND tb[node].attr2 THEN {P5.ReleaseLock[]; monitored ← FALSE}; Stack.Dump[]; Stack.Mark[]; IF tb[node].son[1] = Tree.Null THEN P5U.PushLitVal[-1] ELSE P5.PushRhs[tb[node].son[1]]; nparms ← PushParms[FALSE, tb[node].son[2], ptsei, TRUE, FALSE]; IF monitored THEN BEGIN Stack.Dump[]; P5.ReleaseLock[]; Stack.Load[Stack.Top[2],2]; END; IF tb[node].attr3 THEN -- inline expanded BEGIN SysCall[IF nparms > 1 THEN SDDefs.sErrorList ELSE SDDefs.sError]; ChainCatch[CPtr.substenable]; END ELSE SysCall[IF nparms > 1 THEN SDDefs.sReturnErrorList ELSE SDDefs.sReturnError]; P5U.OutJump[JumpRet,LabelCCNull]; END; CodeInline: PROC [t: Tree.Link] = BEGIN opByte: ARRAY [0..7) OF Byte; iLength: CARDINAL ← 0; tLength: CARDINAL; c: CodeCCIndex; PickUpByte: PROC [t: Tree.Link] = BEGIN IF iLength < 7 THEN BEGIN opByte[iLength] ← WITH t SELECT FROM symbol => seb[index].idValue, ENDCASE => P5U.TreeLiteralValue[t]; iLength ← iLength + 1; END ELSE Log.Error[instLength]; END; TreeOps.ScanList[t, PickUpByte]; IF iLength = 0 THEN RETURN; tLength ← OpTableDefs.InstLength[opByte[0]]; IF tLength # 0 AND iLength # tLength THEN Log.Warning[instLength]; c ← P5U.AllocCodeCCItem[iLength-1]; cb[c].realinst ← TRUE; cb[c].inst ← opByte[0]; cb[c].isize ← iLength; FOR i: CARDINAL IN [1..iLength) DO cb[c].parameters[i] ← opByte[i] ENDLOOP; END; PushParms: PROC [ argsBuilt: BOOL, t: Tree.Link, ptsei: CSEIndex, sigerr: BOOL, refSafe: BOOL←TRUE] RETURNS [nparms: CARDINAL] = BEGIN rsei: RecordSEIndex = SymbolOps.TransferTypes[ptsei].typeIn; RETURN [IF argsBuilt THEN PushArgRecord[t, rsei, sigerr, FALSE, refSafe] ELSE BuildArgRecord[t, rsei, sigerr, FALSE, refSafe]] END; BuildArgRecord: PUBLIC PROC [ t: Tree.Link, rsei: RecordSEIndex, sigerr, isResume, refSafe: BOOL] RETURNS [nparms: CARDINAL] = BEGIN nparms ← IF rsei = Symbols.SENull THEN 0 ELSE P5U.WordsForSei[rsei]; IF nparms > MaxParmsInStack OR (sigerr AND nparms > 1) THEN BEGIN IF ~(refSafe OR Counting.CheckArgRefs[t, rsei]) THEN Log.Warning[unsafeArgs]; P5.TransferConstruct[nparms, bb[MPtr.bodyIndex].resident, t, rsei]; END ELSE IF sigerr AND ~isResume AND nparms = 0 THEN P5U.PushLitVal[-1] ELSE IF nparms # 0 THEN ConstructOnStack[t, rsei]; RETURN END; PushArgRecord: PUBLIC PROC [ t: Tree.Link, rsei: RecordSEIndex, sigerr, isResume, refSafe: BOOL] RETURNS [nparms: CARDINAL] = BEGIN offStack: BOOL; frameExists: BOOL ← FALSE; nparms ← IF rsei = Symbols.SENull THEN 0 ELSE P5U.WordsForSei[rsei]; offStack ← (nparms > MaxParmsInStack OR (sigerr AND nparms > 1)); IF t # Tree.Null THEN BEGIN l: Lexeme; refSafe ← refSafe OR Counting.CheckArgRefs[t, rsei]; l ← P5.Exp[t ! LogHeapFree => IF calltree = t AND offStack THEN {frameExists ← TRUE; RESUME [TRUE, NullLex]} ELSE RESUME [FALSE, NullLex] ]; SELECT TRUE FROM frameExists => P5L.ReleaseLex[l]; offStack => BEGIN source: VarIndex = P5L.VarForLex[l]; dest: VarIndex; temp: VarComponent; fs: CARDINAL ← P5U.ComputeFrameSize[nparms]; IF bb[MPtr.bodyIndex].resident THEN fs ← fs + PrincOps.AllocationVectorSize; IF ~refSafe THEN Log.Warning[unsafeArgs]; P5U.PushLitVal[fs]; P5U.Out0[FOpCodes.qALLOC]; temp ← Stack.TempStore[1]; dest ← P5L.GenVarItem[bo]; cb[dest] ← [body: bo[base: temp, offset: [wSize: nparms, space: frame[]]]]; l ← P5L.VarVarAssign[to: dest, from: source, isexp: FALSE]; P5L.LoadComponent[temp]; END; ENDCASE => P5.PushLex[l]; END ELSE IF sigerr AND ~isResume THEN P5U.PushLitVal[-1]; RETURN END; Call: PUBLIC PROC [node: Tree.Index] = {[] ← SCall[node]}; SigErr: PUBLIC PROC [node: Tree.Index] = BEGIN error: BOOL = (tb[node].name = error); [] ← SSigErr[node, error]; IF error THEN P5U.OutJump[JumpRet,LabelCCNull]; END; CallExp: PUBLIC PROC [node: Tree.Index] RETURNS [Lexeme] = BEGIN nrets: CARDINAL = SCall[node]; RETURN [PRetLex[nrets, node, FALSE]]; END; LogHeapFree: PUBLIC SIGNAL [calltree: Tree.Link] RETURNS [BOOL, Lexeme.se] = CODE; IndirectReturnRecord: PUBLIC PROC [node: Tree.Index, nrets: CARDINAL] RETURNS [Lexeme] = BEGIN -- also called by SubstExp OPEN FOpCodes; tlex, hlex: Lexeme.se; logged: BOOL; [logged, hlex] ← SIGNAL LogHeapFree[[subtree[node]]]; IF ~logged THEN BEGIN tlex ← P5.GenTempLex[1]; P5.SAssign[tlex.lexsei]; P5U.Out0[qPUSH]; hlex ← P5.GenTempLex[nrets]; P5U.PushLitVal[nrets]; [] ← P5L.LoadAddress[P5L.VarForLex[hlex]]; P5U.Out0[qBLT]; P5.PushLex[tlex]; P5U.Out0[qFREE]; RETURN [hlex] END; IF hlex # NullLex THEN BEGIN P5.SAssign[hlex.lexsei]; P5.PushLex[hlex]; -- will become PUSH, helps stack model END; RETURN [P5L.TOSAddrLex[nrets, FALSE]] END; SigExp: PUBLIC PROC [node: Tree.Index] RETURNS [Lexeme] = BEGIN nrets: CARDINAL = SSigErr[node, FALSE]; RETURN [PRetLex[nrets, node, TRUE]] END; ErrExp: PUBLIC PROC [node: Tree.Index] RETURNS [Lexeme] = BEGIN nrets: CARDINAL = P5U.WordsForSei[tb[node].info]; [] ← SSigErr[node, TRUE]; P5U.OutJump[JumpRet,LabelCCNull]; RETURN [PRetLex[nrets, node, TRUE]] END; SysCall: PUBLIC PROC [alpha: Byte] = BEGIN -- puts out call via system transfer vector Stack.DeleteToMark[]; P5U.Out1[FOpCodes.qKFCB, alpha]; END; SysCallN: PUBLIC PROC [alpha: Byte, n: CARDINAL] = BEGIN -- puts out call via system transfer vector Stack.DeleteToMark[]; P5U.Out1[FOpCodes.qKFCB, alpha]; Stack.Incr[n]; END; Wait: PUBLIC PROC [node: Tree.Index] = BEGIN OPEN FOpCodes; retry: LabelCCIndex; t1Long: BOOL = P5U.LongTreeAddress[tb[node].son[1]]; t2Long: BOOL = P5U.LongTreeAddress[tb[node].son[2]]; longWait: BOOL = t1Long OR t2Long; [] ← P5L.LoadAddress[P5L.VarForLex[P5.Exp[tb[node].son[1]]]]; IF ~t1Long AND t2Long THEN P5U.Out0[qLP]; [] ← P5L.LoadAddress[P5L.VarForLex[P5.Exp[tb[node].son[2]]]]; IF ~longWait THEN BEGIN P5U.Out0[qDUP]; P5U.Out1[qR,1]; -- load timeout P5U.Out0[qMXW]; END ELSE BEGIN IF ~t2Long THEN P5U.Out0[qLP]; [] ← P5L.LoadAddress[P5L.VarForLex[P5.Exp[tb[node].son[2]]]]; P5U.Out1[IF t2Long THEN qRL ELSE qR, 1]; P5U.Out0[qMXWL]; END; retry ← P5U.CreateLabel[]; [] ← P5L.LoadAddress[P5L.VarForLex[P5.Exp[tb[node].son[1]]]]; IF longWait AND ~t1Long THEN P5U.Out0[qLP]; [] ← P5L.LoadAddress[P5L.VarForLex[P5.Exp[tb[node].son[2]]]]; IF longWait AND ~t2Long THEN P5U.Out0[qLP]; P5U.Out0[IF longWait THEN qMREL ELSE qMRE]; CallCatch[IF tb[node].nSons > 2 THEN tb[node].son[3] ELSE Tree.Null]; P5U.Out1[FOpCodes.qLI, 0]; P5U.OutJump[JumpE, retry]; END; ForkExp: PUBLIC PROC [node: Tree.Index] RETURNS [Lexeme] = BEGIN ptsei: CSEIndex = P5U.OperandType[tb[node].son[1]]; Stack.Dump[]; Stack.Mark[]; [] ← PushParms[tb[node].attr1, tb[node].son[2], ptsei, FALSE, FALSE]; P5.PushRhs[tb[node].son[1]]; SysCall[IF MPtr.switches['c] THEN RTSD.sFork ELSE SDDefs.sFork]; CallCatch[IF tb[node].nSons > 2 THEN tb[node].son[3] ELSE Tree.Null]; Stack.Incr[1]; RETURN [P5L.TOSLex[1]] END; SJoin: PUBLIC PROC [node: Tree.Index] RETURNS [nrets: CARDINAL] = BEGIN ptsei: CSEIndex = P5U.OperandType[tb[node].son[1]]; Stack.Dump[]; Stack.Mark[]; P5.PushRhs[tb[node].son[1]]; SysCall[SDDefs.sJoin]; IF tb[node].nSons > 2 THEN BEGIN saveCfSize: CARDINAL = CPtr.cfSize; saveCfsi: CARDINAL = CPtr.cfsi; cr: CodeCCIndex; aroundlabel, firstcatch: LabelCCIndex; aroundlabel ← P5U.LabelAlloc[]; firstcatch ← P5U.LabelAlloc[]; CPtr.catchcount ← CPtr.catchcount + 1; P5U.Out1[FOpCodes.qCATCH, 0]; cr ← LOOPHOLE[CPtr.codeptr, CodeCCIndex]; P5U.OutJump[JumpA, aroundlabel]; P5U.InsertLabel[firstcatch]; P5.SCatchPhrase[TreeOps.GetNode[tb[node].son[3]]]; cb[cr].parameters[1] ← CPtr.cfsi; P5U.InsertLabel[aroundlabel]; CPtr.catchcount ← CPtr.catchcount - 1; Stack.Incr[1]; P5U.Out0[FOpCodes.qSFC]; aroundlabel ← P5U.LabelAlloc[]; P5U.Out1[FOpCodes.qCATCH, CPtr.cfsi]; P5U.OutJump[JumpA, aroundlabel]; P5U.OutJump[Jump, firstcatch]; P5U.InsertLabel[aroundlabel]; CPtr.cfSize ← saveCfSize; CPtr.cfsi ← saveCfsi; END ELSE BEGIN CallCatch[Tree.Null]; Stack.Incr[1]; P5U.Out0[FOpCodes.qSFC]; CallCatch[Tree.Null]; END; RETURN [P5U.WordsForSei[SymbolOps.TransferTypes[ptsei].typeOut]] END; JoinExp: PUBLIC PROC [node: Tree.Index] RETURNS [Lexeme] = BEGIN nrets: CARDINAL = SJoin[node]; RETURN [PRetLex[nrets, node, FALSE]] END; Join: PUBLIC PROC [node: Tree.Index] = {[] ← SJoin[node]}; Unlock: PUBLIC PROC [node: Tree.Index] = BEGIN mlock: Tree.Link = tb[node].son[1]; IF mlock # Tree.Null THEN BEGIN long: BOOL = P5L.LoadAddress[P5L.VarForLex[P5.Exp[mlock]]]; P5U.Out0[IF long THEN FOpCodes.qMXDL ELSE FOpCodes.qMXD]; END; END; ProcCheck: PUBLIC PROC [node: Tree.Index] RETURNS [Lexeme] = BEGIN Stack.Dump[]; Stack.Mark[]; P5.PushRhs[tb[node].son[1]]; SysCallN[RTSD.sProcCheck, 1]; RETURN [P5L.TOSLex[1]] END; PRetLex: PUBLIC PROC [nrets: CARDINAL, node: Tree.Index, sig: BOOL ← FALSE] RETURNS [Lexeme] = BEGIN IF nrets > MaxParmsInStack OR sig AND nrets > 1 THEN BEGIN Stack.Incr[1]; RETURN [IndirectReturnRecord[node, nrets]] END ELSE BEGIN Stack.Incr[nrets]; RETURN [P5L.TOSLex[nrets]] END END; Free: PUBLIC PROC [node: Tree.Index] = BEGIN countedVar: BOOL = tb[node].attr1; counted: BOOL = tb[node].attr3; zoneLink: Tree.Link = tb[node].son[1]; varLink: Tree.Link = tb[node].son[2]; catchLink: Tree.Link = IF tb[node].nSons > 3 THEN tb[node].son[4] ELSE Tree.Null; r: VarIndex ← P5L.VarForLex[P5.Exp[varLink]]; IF counted THEN Counting.Free[r, countedVar, zoneLink, catchLink] ELSE BEGIN rr: VarIndex; pLength: CARDINAL = P5U.WordsForOperand[varLink]; c0: VarIndex ← P5L.OVarItem[[wSize: pLength, space: const[d1:0, d2:0]]]; long: BOOL = tb[node].attr2; bor: BoVarIndex ← P5L.MakeBo[r]; PushVar: PROC = BEGIN P5L.LoadVar[bor]; [] ← P5L.VarVarAssign[rr, c0, FALSE]; END; cb[bor].base ← P5L.EasilyLoadable[cb[bor].base, load]; rr ← P5L.CopyVarItem[bor]; ZoneOp[zoneLink, 1, PushVar, catchLink, long]; END; END; ZoneOp: PUBLIC PROC [ zone: Tree.Link, index: CARDINAL, pushArg: PROC, catch: Tree.Link, long: BOOL] = BEGIN z, zCopy: VarIndex; z ← P5L.VarForLex[P5.Exp[zone]]; [first: z, next: zCopy] ← P5L.ReusableCopies[z, load, FALSE]; Stack.Dump[]; Stack.Mark[]; P5L.LoadVar[z]; pushArg[]; P5L.LoadVar[zCopy]; IF long THEN {P5U.Out1[FOpCodes.qRDL, 0]; P5U.Out1[FOpCodes.qRL, index]} ELSE {P5U.Out1[FOpCodes.qR, 0]; P5U.Out1[FOpCodes.qR, index]}; Stack.DeleteToMark[]; Stack.Incr[1]; P5U.Out0[FOpCodes.qSFC]; CallCatch[catch]; END; END.