-- file Pass3P.mesa -- last modified by Satterthwaite, July 27, 1983 2:24 pm DIRECTORY Alloc: TYPE USING [Notifier, AddNotify, DropNotify, Top, Words], ComData: TYPE USING [ defBodyLimit, interface, nBodies, nInnerBodies, table, textIndex, zone], CompilerUtil: TYPE USING [], Log: TYPE USING [Error, ErrorSei], Symbols: TYPE USING [ Base, BodyInfo, BodyRecord, ContextLevel, SERecord, ISEIndex, CSEIndex, RecordSEIndex, CTXIndex, BTIndex, CBTIndex, nullName, ISENull, CSENull, RecordSENull, CTXNull, BTNull, lL, lZ, RootBti, typeTYPE, seType, ctxType, mdType, bodyType], SymbolOps: TYPE USING [ ArgCtx, CopyArgSe, CopyXferType, CtxEntries, DelinkBti, FindExtension, FirstCtxSe, LinkBti, MakeNonCtxSe, MakeSeChain, NewCtx, NextLevel, NextSe, ParentBti, SetSeLink, SearchContext, TransferTypes, StaticNestError], Tree: TYPE USING [Base, Index, Link, Map, Scan, Null, NullIndex, treeType], TreeOps: TYPE USING [ CopyTree, FreeNode, FreeTree, GetNode, ListTail, MakeList, MarkShared, NthSon, OpName, PopTree, PushList, PushNode, PushTree, ScanList, ScanSons, SetAttr, SetInfo, Shared, UpdateList, UpdateLeaves]; Pass3P: PROGRAM IMPORTS Alloc, Log, SymbolOps, TreeOps, dataPtr: ComData EXPORTS CompilerUtil = { OPEN TreeOps, SymbolOps, Symbols; tb: Tree.Base; -- tree base address (local copy) seb: Symbols.Base; -- se table base address (local copy) ctxb: Symbols.Base; -- context table base address (local copy) mdb: Symbols.Base; -- module table base address (local copy) bb: Symbols.Base; -- body table base address (local copy) PostNotify: Alloc.Notifier = { -- called by allocator whenever table area is repacked tb ← base[Tree.treeType]; seb ← base[seType]; ctxb ← base[ctxType]; mdb ← base[mdType]; bb ← base[bodyType]}; -- driver P3Postlude: PUBLIC PROC [expand: BOOL] = { (dataPtr.table).AddNotify[PostNotify]; IF expand THEN {LinkImportedBodies[]; ExpandInlines[RootBti]}; (dataPtr.table).DropNotify[PostNotify]}; -- included body copying LinkImportedBodies: PROC = { next: BTIndex; btLimit: BTIndex = (dataPtr.table).Top[bodyType]; FOR bti: BTIndex ← LOOPHOLE[dataPtr.defBodyLimit], next UNTIL bti = btLimit DO WITH body: bb[bti] SELECT FROM Callable => { IF body.inline THEN {body.link ← bb[RootBti].link; bb[RootBti].link ← [sibling, bti]}; next ← bti + (SELECT body.nesting FROM Inner => BodyRecord.Callable.Inner.SIZE, Catch => BodyRecord.Callable.Catch.SIZE, ENDCASE => BodyRecord.Callable.Outer.SIZE)}; ENDCASE => next ← bti + BodyRecord.Other.SIZE; ENDLOOP}; -- inline expansion -- state information currentMaster: CBTIndex; masterBody: Tree.Index; copyCtx: CTXIndex; copying: BOOL; substSafe: BOOL; currentEnclosing: BTIndex; bodyNesting: CARDINAL; aStack: AList; -- current association list AItem: TYPE = RECORD [id: ISEIndex, name: BOOL, val: Tree.Link]; ANode: TYPE = RECORD [ next: AList, ctx: CTXIndex, nItems: CARDINAL, map: SEQUENCE maxItems: CARDINAL OF AItem]; AList: TYPE = LONG POINTER TO ANode; -- overall control ExpandInlines: PROC [rootBti: BTIndex] = { bti: BTIndex ← rootBti; aStack ← NIL; sharingMap ← NIL; UNTIL bti = BTNull DO ExpandInlines[bb[bti].firstSon]; WITH body: bb[bti] SELECT FROM Callable => IF body.inline THEN ExpandCalls[LOOPHOLE[bti, CBTIndex]]; ENDCASE; bti ← IF bb[bti].link.which=parent THEN BTNull ELSE bb[bti].link.index; ENDLOOP}; ExpandCalls: PROC [bti: CBTIndex] = { saveIndex: CARDINAL = dataPtr.textIndex; sei: ISEIndex = bb[bti].id; current, subNode: Tree.Index; dataPtr.textIndex ← bb[bti].sourceIndex; WITH body: bb[bti].info SELECT FROM Internal => { currentMaster ← bti; IF seb[sei].mark4 THEN { t: Tree.Link = FindExtension[sei].tree; ComputeArgCounts[bb[bti].ioType, t]; masterBody ← GetNode[t]} ELSE masterBody ← body.bodyTree; copying ← TRUE; UNTIL (current ← body.thread) = Tree.NullIndex DO discard: BOOL; -- process the thread (son[1]) subNode ← GetNode[tb[current].son[1]]; discard ← tb[subNode].attr1; tb[current].son[1] ← tb[subNode].son[1]; currentEnclosing ← tb[subNode].info; body.thread ← GetNode[tb[subNode].son[2]]; tb[subNode].son[1] ← tb[subNode].son[2] ← Tree.Null; FreeNode[subNode]; tb[current].shared ← FALSE; IF body.thread = Tree.NullIndex AND (~dataPtr.interface OR bb[bti].level > lL) THEN copying ← FALSE; SELECT TRUE FROM discard => DiscardCall[current]; ~RecursiveSubst[bti, currentEnclosing] => ExpandCall[current] ENDCASE => Log.ErrorSei[recursiveInline, bb[bti].id]; ENDLOOP}; ENDCASE => ERROR; dataPtr.textIndex ← saveIndex}; DiscardCall: PROC [node: Tree.Index] = INLINE { -- orphan subtree [] ← DiscardTree[[subtree[node]]]}; ExpandCall: PROC [node: Tree.Index] = { typeIn, typeOut: RecordSEIndex; masterCtx: CTXIndex = bb[currentMaster].localCtx; formalCtx: CTXIndex; seChain, saveChain: ISEIndex; nAssigns, nVars: CARDINAL; extendedScope: BOOL; newBti: BTIndex; t: Tree.Link; IF tb[node].name = call THEN dataPtr.textIndex ← tb[node].info; bodyNesting ← 0; IF copying OR masterCtx = CTXNull THEN copyCtx ← CTXNull ELSE { saveChain ← ctxb[masterCtx].seList; ctxb[masterCtx].seList ← ISENull; ctxb[masterCtx].level ← bb[currentEnclosing].level; copyCtx ← masterCtx}; [typeIn, typeOut] ← TransferTypes[bb[currentMaster].ioType]; substSafe ← tb[node].attr3 AND bb[currentMaster].hints.nameSafe; nAssigns ← SELECT TRUE FROM (typeIn = RecordSENull) => 0, tb[node].attr1 => ExtractArgs[typeIn, seb[typeIn].fieldCtx, node], ENDCASE => MapArgs[seb[typeIn].fieldCtx, node]; tb[node].son[2] ← FreeTree[tb[node].son[2]]; IF RequiredFields[typeOut] THEN { formalCtx ← seb[typeOut].fieldCtx; IF copyCtx = CTXNull THEN copyCtx ← NewCtx[bb[currentEnclosing].level]; seChain ← MakeSeChain[copyCtx, CtxVars[formalCtx], TRUE]; AppendSeChain[copyCtx, seChain]; MapIds[formalCtx, seChain, 0]}; IF tb[masterBody].son[1] # Tree.Null THEN PushTree[ExpandOpens[tb[masterBody].son[1]]]; IF masterCtx # CTXNull THEN IF ~copying THEN AppendSeChain[copyCtx, saveChain] ELSE IF (nVars ← CtxVars[masterCtx]) # 0 THEN { IF copyCtx = CTXNull THEN copyCtx ← NewCtx[bb[currentEnclosing].level]; seChain ← MakeSeChain[copyCtx, nVars, FALSE]; MapIds[masterCtx, seChain, 0]; AppendSeChain[copyCtx, seChain]}; -- expand the body IF copyCtx # CTXNull THEN newBti ← MakeEnclosingBody[BTNull, copyCtx]; t ← ExpandDecls[tb[masterBody].son[2]]; PushTree[ExpandTree[tb[masterBody].son[3]]]; IF copyCtx = CTXNull THEN extendedScope ← FALSE ELSE { extendedScope ← nAssigns # 0 OR tb[masterBody].son[1] # Tree.Null OR tb[masterBody].son[4] # Tree.Null; PushTree[t]; PushNode[block, -2]; SetInfo[newBti]; SetAttr[3, extendedScope]; SetAttr[1, tb[masterBody].attr1]; SetAttr[2, tb[masterBody].attr2]; WITH body: bb[newBti].info SELECT FROM Internal => {body.bodyTree ← GetNode[t←PopTree[]]; PushTree[t]}; ENDCASE => ERROR}; IF tb[masterBody].son[1] # Tree.Null THEN { PushNode[open, 2]; SetInfo[dataPtr.textIndex]}; IF tb[masterBody].son[4] # Tree.Null THEN { PushTree[ExpandTree[tb[masterBody].son[4]]]; PushNode[lock, 2]; SetInfo[dataPtr.textIndex]}; IF masterCtx # CTXNull AND copying AND nVars # 0 THEN UnmapIds[explicit]; IF copyCtx # CTXNull THEN currentEnclosing ← ParentBti[currentEnclosing]; IF ~copying THEN PruneBody[masterBody]; -- complete the setup IF tb[node].nSons > 2 THEN { PushTree[tb[node].son[3]]; tb[node].son[3] ← Tree.Null; PushNode[enable, -2]; SetInfo[dataPtr.textIndex]; SetAttr[3, TRUE]}; IF RequiredFields[typeOut] THEN UnmapIds[implicit]; IF typeIn # RecordSENull THEN UnmapIds[implicit]; tb[node].son[2] ← MakeList[nAssigns+1]; IF copyCtx # CTXNull AND nAssigns # 0 THEN UpdateBodyNesting[tb[node].son[2], newBti]; tb[node].name ← IF tb[node].name = callx THEN substx ELSE subst; tb[node].attr1 ← tb[masterBody].attr1; tb[node].attr2 ← tb[masterBody].attr2; tb[node].attr3 ← extendedScope; ResetSharing[]}; RecursiveSubst: PROC [bti, parent: BTIndex] RETURNS [BOOL] = { UNTIL parent = BTNull DO IF bti = parent THEN RETURN [TRUE]; parent ← ParentBti[parent]; ENDLOOP; RETURN [FALSE]}; PruneBody: PROC [node: Tree.Index] = { OPEN tb[node]; son[1] ← son[2] ← son[3] ← son[4] ← Tree.Null; name ← procinit}; -- argument list testing/processing NameSafe: PROC [t: Tree.Link] RETURNS [safe: BOOL] = { RETURN [~bb[currentMaster].hints.argUpdated AND (substSafe OR (WITH t SELECT FROM symbol => seb[index].immutable, literal => TRUE, ENDCASE => SELECT OpName[t] FROM IN [relE..relLE], IN [plus..mod] => NameSafe[NthSon[t, 1]] AND NameSafe[NthSon[t, 2]], not, uminus, abs, pred, succ => NameSafe[NthSon[t, 1]], loophole, cast, check, lengthen, shorten, float => NameSafe[NthSon[t, 1]], clit, llit, mwconst, nil, atom => TRUE, cdot => NameSafe[NthSon[t, 2]], ENDCASE => FALSE))]}; VarRefs: PROC [sei: ISEIndex] RETURNS [CARDINAL] = INLINE { RETURN [seb[sei].idInfo]}; CheapEval: PROC [t: Tree.Link, top: BOOL←TRUE] RETURNS [BOOL] = { RETURN [WITH t SELECT FROM subtree => SELECT OpName[t] FROM clit, llit, mwconst, nil, atom => TRUE, loophole, cast, openx => CheapEval[NthSon[t, 1], top], addr, uparrow, dot, dollar => CheapEval[NthSon[t, 1], top], IN [index .. reloc] => CheapEval[NthSon[t, 1], FALSE] AND CheapEval[NthSon[t, 2], FALSE], IN [or .. mod] => top AND CheapEval[NthSon[t, 1], FALSE] AND CheapEval[NthSon[t, 2], FALSE], not, uminus, abs, pred, succ, lengthen, shorten => top AND CheapEval[NthSon[t, 1], FALSE], cdot => CheapEval[NthSon[t, 2], top], ENDCASE => FALSE, ENDCASE => TRUE]}; MapByName: PROC [sei: ISEIndex, t: Tree.Link] RETURNS [BOOL] = { n: CARDINAL = VarRefs[sei]; RETURN [NameSafe[t] AND (n <= 2 OR CheapEval[t])]}; CountVars: PROC [ctx: CTXIndex, t: Tree.Link] RETURNS [n: CARDINAL ← 0] = { sei: ISEIndex ← FirstCtxSe[ctx]; CountVar: Tree.Scan = { IF sei # ISENull THEN {IF ~MapByName[sei, t] THEN n ← n+1; sei ← NextSe[sei]}}; ScanList[t, CountVar]; RETURN}; RequiredFields: PROC [rSei: RecordSEIndex] RETURNS [BOOL] = { FOR sei: ISEIndex ← FirstCtxSe[FieldCtx[rSei]], NextSe[sei] UNTIL sei = ISENull DO IF seb[sei].hash = nullName THEN RETURN [FALSE]; IF seb[sei].idInfo # 0 THEN RETURN [TRUE]; ENDLOOP; RETURN [FALSE]}; -- tree manipulation DiscardTree: Tree.Map = { IF t # Tree.Null THEN WITH t SELECT FROM subtree => { node: Tree.Index ← index; SELECT tb[node].name FROM call, callx => IF OpName[tb[node].son[1]] = thread THEN { -- mark for later discard (see DiscardCall) subNode: Tree.Index = GetNode[tb[node].son[1]]; tb[subNode].attr1 ← TRUE} ELSE { [] ← UpdateLeaves[t, DiscardTree]; FreeNode[node]}; ENDCASE => IF ~tb[node].shared THEN { [] ← UpdateLeaves[t, DiscardTree]; FreeNode[node]}}; ENDCASE; RETURN [Tree.Null]}; ExpandTree: Tree.Map = { WITH t SELECT FROM symbol => v ← ExpandSei[index]; subtree => { sNode: Tree.Index = index; IF tb[sNode].shared THEN v ← SELECT tb[sNode].name FROM call, callx => ExpandThreadedCall[sNode], ENDCASE => ExpandShared[sNode] ELSE SELECT tb[sNode].name FROM body => v ← ExpandBody[sNode]; block => v ← ExpandBlock[sNode, tb[sNode].attr3]; catch => v ← ExpandCatch[sNode]; ditem => v ← ExpandBlock[sNode, FALSE]; do => v ← ExpandDo[sNode]; open, bind, bindx => v ← ExpandBinding[sNode]; subst, substx => v ← ExpandSubst[sNode]; lock => v ← ExpandLock[sNode]; thread => v ← ExpandThread[sNode]; ENDCASE => { v ← IF copying THEN CopyTree[[baseP:@tb, link:t], ExpandTree] ELSE UpdateLeaves[t, ExpandTree]; WITH v SELECT FROM subtree => { dNode: Tree.Index = index; SELECT tb[dNode].name FROM return => IF bodyNesting = 0 THEN UpdateReturn[dNode]; xerror => IF bodyNesting = 0 THEN tb[dNode].attr3 ← TRUE; ENDCASE => NULL}; ENDCASE => NULL}}; ENDCASE => v ← t; RETURN}; RewriteNode: PROC [node: Tree.Index, nSons: CARDINAL] RETURNS [Tree.Link] = { FOR i: CARDINAL DECREASING IN [1 .. nSons] DO tb[node].son[i] ← PopTree[] ENDLOOP; RETURN [[subtree[index: node]]]}; CopyNode: PROC [node: Tree.Index, nSons: CARDINAL] RETURNS [Tree.Link] = { PushNode[tb[node].name, nSons]; SetInfo[tb[node].info]; SetAttr[1, tb[node].attr1]; SetAttr[2, tb[node].attr2]; SetAttr[3, tb[node].attr3]; RETURN [PopTree[]]}; ExpandBlock: PROC [node: Tree.Index, extendedScope: BOOL] RETURNS [v: Tree.Link] = { EnterBlock[node, extendedScope]; PushTree[ExpandDecls[tb[node].son[1]]]; PushTree[ExpandTree[tb[node].son[2]]]; v ← IF copying THEN CopyNode[node, 2] ELSE RewriteNode[node, 2]; ExitBlock[GetNode[v]]; RETURN}; ExpandBody: PROC [node: Tree.Index] RETURNS [v: Tree.Link] = { EnterBody[node]; PushTree[ExpandOpens[tb[node].son[1]]]; PushTree[ExpandDecls[tb[node].son[2]]]; PushTree[ExpandTree[tb[node].son[3]]]; PushTree[ExpandTree[tb[node].son[4]]]; v ← IF copying THEN CopyNode[node, 4] ELSE RewriteNode[node, 4]; ExitBody[GetNode[v]]; RETURN}; ExpandCatch: PROC [node: Tree.Index] RETURNS [v: Tree.Link] = { EnterCatch[node]; PushTree[ExpandTree[tb[node].son[1]]]; PushTree[ExpandTree[tb[node].son[2]]]; v ← IF copying THEN CopyNode[node, 2] ELSE RewriteNode[node, 2]; ExitCatch[GetNode[v]]; RETURN}; ExpandDo: PROC [node: Tree.Index] RETURNS [v: Tree.Link] = { decl: BOOL; subNode: Tree.Index; IF tb[node].son[1] = Tree.Null THEN decl ← FALSE ELSE {subNode ← GetNode[tb[node].son[1]]; decl ← OpName[tb[subNode].son[1]] = decl}; IF decl THEN { nSons: CARDINAL = tb[subNode].nSons; EnterBlock[subNode, FALSE]; PushTree[ExpandDecls[tb[subNode].son[1]]]; FOR i: CARDINAL IN [2..nSons] DO PushTree[ExpandTree[tb[subNode].son[i]]] ENDLOOP; IF copying THEN {PushNode[tb[subNode].name, nSons]; SetInfo[tb[subNode].info]} ELSE PushTree[RewriteNode[subNode, nSons]]} ELSE PushTree[ExpandTree[tb[node].son[1]]]; PushTree[ExpandTree[tb[node].son[2]]]; PushTree[ExpandOpens[tb[node].son[3]]]; FOR i: CARDINAL IN [4..6] DO PushTree[ExpandTree[tb[node].son[i]]] ENDLOOP; v ← IF copying THEN CopyNode[node, 6] ELSE RewriteNode[node, 6]; IF decl THEN { newNode: Tree.Index = GetNode[v]; ExitBlock[GetNode[tb[newNode].son[1]], newNode]}; RETURN}; ExpandBinding: PROC [node: Tree.Index] RETURNS [Tree.Link] = { nSons: CARDINAL = tb[node].nSons; PushTree[ExpandOpens[tb[node].son[1]]]; FOR i: CARDINAL IN [2..nSons] DO PushTree[ExpandTree[tb[node].son[i]]] ENDLOOP; RETURN [IF copying THEN CopyNode[node, nSons] ELSE RewriteNode[node, nSons]]}; ExpandSubst: PROC [node: Tree.Index] RETURNS [Tree.Link] = { extendedScope: BOOL = tb[node].attr3; PushTree[ExpandTree[tb[node].son[1]]]; IF extendedScope THEN MapBlock[FindBlock[tb[node].son[2]]]; PushTree[ExpandTree[tb[node].son[2]]]; RETURN [IF copying THEN CopyNode[node, 2] ELSE RewriteNode[node, 2]]}; ExpandThreadedCall: PROC [node: Tree.Index] RETURNS [v: Tree.Link] = { nSons: CARDINAL = tb[node].nSons; FOR i: CARDINAL IN [1 .. nSons] DO PushTree[ExpandTree[tb[node].son[i]]] ENDLOOP; v ← IF copying THEN CopyNode[node, nSons] ELSE RewriteNode[node, nSons]; ThreadSubst[node, v]; RETURN}; ExpandThread: PROC [node: Tree.Index] RETURNS [v: Tree.Link] = { IF ~copying THEN {tb[node].son[1] ← ExpandTree[tb[node].son[1]]; v ← [subtree[node]]} ELSE { PushTree[ExpandTree[tb[node].son[1]]]; PushTree[Tree.Null]; PushNode[thread, 2]; SetInfo[tb[node].info]; v ← PopTree[]}; RETURN}; ExpandLock: PROC [node: Tree.Index] RETURNS [v: Tree.Link] = { PushTree[ExpandTree[tb[node].son[2]]]; PushTree[ExpandTree[tb[node].son[1]]]; IF copying THEN {PushNode[lock, -2]; SetInfo[tb[node].info]; v ← PopTree[]} ELSE { tb[node].son[1] ← PopTree[]; tb[node].son[2] ← PopTree[]; v ← [subtree[index: node]]}; RETURN}; UpdateReturn: PROC [node: Tree.Index] = { typeOut: RecordSEIndex; IF tb[node].son[1] = Tree.Null AND (typeOut←TransferTypes[bb[currentMaster].ioType].typeOut) # RecordSENull THEN { n: CARDINAL ← 0; FOR sei: ISEIndex ← FirstCtxSe[FieldCtx[typeOut]], NextSe[sei] UNTIL sei = ISENull DO PushTree[ExpandSei[sei]]; n ← n+1 ENDLOOP; tb[node].son[1] ← MakeList[n]}; tb[node].name ← result}; ExpandDecls: Tree.Map = { n: CARDINAL; ExpandDecl: Tree.Scan = { node: Tree.Index; LinkDecl: Tree.Scan = { WITH t SELECT FROM symbol => { sei: ISEIndex = index; seb[sei].idValue ← node; IF ~seb[sei].mark4 AND tb[node].son[3] = Tree.Null AND ~seb[sei].immutable THEN seb[sei].idInfo ← seb[sei].idInfo - 1}; ENDCASE}; copy: Tree.Link; IF OpName[t] # typedecl THEN { PushTree[copy ← ExpandTree[t]]; n ← n+1; node ← GetNode[copy]; ScanList[tb[node].son[1], LinkDecl]}}; IF OpName[t] = initlist THEN { node: Tree.Index = GetNode[t]; PushTree[ExpandTree[tb[node].son[1]]]; PushTree[ExpandDecls[tb[node].son[2]]]; IF copying THEN {PushNode[initlist, 2]; SetInfo[tb[node].info]; v ← PopTree[]} ELSE v ← RewriteNode[node, 2]} ELSE IF copying THEN {n ← 0; ScanList[t, ExpandDecl]; v ← MakeList[n]} ELSE v ← ExpandTree[t]; RETURN}; SharingItem: TYPE = RECORD [old, new: Tree.Link, next: SharingList]; SharingList: TYPE = LONG POINTER TO SharingItem; sharingMap: SharingList; MapShared: PROC [t, v: Tree.Link] = { p: SharingList ← (dataPtr.zone).NEW[SharingItem]; p↑ ← [old:t, new:v, next:sharingMap]; sharingMap ← p; MarkShared[v, TRUE]}; ExpandShared: PROC [node: Tree.Index] RETURNS [v: Tree.Link] = { target: Tree.Link = [subtree[index: node]]; UpdateCount: Tree.Scan = { WITH t SELECT FROM symbol => IncrCount[index]; subtree => ScanSons[t, UpdateCount]; ENDCASE => NULL}; FOR p: SharingList ← sharingMap, p.next UNTIL p = NIL DO IF p.old = target THEN GO TO Found; REPEAT Found => v ← p.new; FINISHED => v ← target; ENDLOOP; IF copying THEN UpdateCount[v]; RETURN}; ResetSharing: PROC = { p: SharingList; UNTIL sharingMap = NIL DO p ← sharingMap; sharingMap ← sharingMap.next; (dataPtr.zone).FREE[@p]; ENDLOOP}; ExpandOpens: Tree.Map = { n: CARDINAL; UpdateOpen: Tree.Scan = { node: Tree.Index = GetNode[t]; base: Tree.Link; tb[node].son[1] ← ExpandTree[tb[node].son[1]]; IF ~Shared[base ← tb[node].son[2]] THEN tb[node].son[2] ← ExpandTree[base] ELSE { MarkShared[base, FALSE]; base ← ExpandTree[base]; MarkShared[base, TRUE]; tb[node].son[2] ← base}}; ExpandOpen: Tree.Scan = { node: Tree.Index = GetNode[t]; base: Tree.Link = tb[node].son[2]; copy: Tree.Link; PushTree[ExpandTree[tb[node].son[1]]]; IF ~Shared[base] THEN PushTree[ExpandTree[base]] ELSE { MarkShared[base, FALSE]; PushTree[copy ← ExpandTree[base]]; MarkShared[base, TRUE]; MapShared[base, copy]}; PushNode[item, 2]; SetInfo[tb[node].info]; n ← n+1}; IF ~copying THEN {ScanList[t, UpdateOpen]; v ← t} ELSE {n ← 0; ScanList[t, ExpandOpen]; v ← MakeList[n]}; RETURN}; -- blocks and bodies FindBlock: PROC [t: Tree.Link] RETURNS [node: Tree.Index] = { DO node ← GetNode[t]; SELECT tb[node].name FROM list => t ← ListTail[t]; block => EXIT; open, enable => t ← tb[node].son[2]; lock => t ← tb[node].son[1]; ENDCASE => ERROR; ENDLOOP; RETURN}; EnterBlock: PROC [node: Tree.Index, extendedScope: BOOL] = INLINE { IF ~extendedScope THEN MapBlock[node]}; MapBlock: PROC [node: Tree.Index] = { oldBti: BTIndex = tb[node].info; oldCtx: CTXIndex = bb[oldBti].localCtx; seChain: ISEIndex; newCtx: CTXIndex; SELECT TRUE FROM oldCtx = CTXNull => newCtx ← CTXNull; ~copying => {newCtx ← oldCtx; ctxb[newCtx].level ← bb[currentEnclosing].level}; ENDCASE => { newCtx ← NewCtx[bb[currentEnclosing].level]; seChain ← MakeSeChain[newCtx, CtxVars[oldCtx], FALSE]; AppendSeChain[newCtx, seChain]; MapIds[oldCtx, seChain, 0]}; [] ← MakeEnclosingBody[IF copying THEN BTNull ELSE oldBti, newCtx]; RETURN}; ExitBlock: PROC [node: Tree.Index, bodyNode: Tree.Index ← Tree.NullIndex] = { oldBti: BTIndex = tb[node].info; newBti: BTIndex = currentEnclosing; tb[node].info ← newBti; WITH body: bb[newBti].info SELECT FROM Internal => body.bodyTree ← IF bodyNode = Tree.NullIndex THEN node ELSE bodyNode; ENDCASE; IF copying AND bb[oldBti].localCtx # CTXNull THEN UnmapIds[explicit]; currentEnclosing ← ParentBti[currentEnclosing]}; MakeEnclosingBody: PROC [oldBti: BTIndex, ctx: CTXIndex] RETURNS [newBti: BTIndex] = { newSon: BTIndex; IF oldBti = BTNull THEN { newBti ← (dataPtr.table).Words[bodyType, BodyRecord.Other.SIZE]; newSon ← BTNull} ELSE {newSon ← bb[oldBti].firstSon; DelinkBti[oldBti]; newBti ← oldBti}; bb[newBti] ← BodyRecord[ link: , firstSon: newSon, type: BodyType[ctx], localCtx: ctx, level: bb[currentEnclosing].level, sourceIndex: , info: BodyInfo[Internal[ bodyTree: Tree.NullIndex, thread: Tree.NullIndex, frameSize: ]], extension: Other[relOffset: ]]; LinkBti[bti: newBti, parent: currentEnclosing]; currentEnclosing ← newBti; RETURN}; EnterBody: PROC [node: Tree.Index] = { oldBti: CBTIndex = tb[node].info; newBti: CBTIndex; ioType: CSEIndex; type: RecordSEIndex; level: ContextLevel = NextLevel[bb[currentEnclosing].level ! StaticNestError => {Log.Error[staticNesting]; RESUME}]; SetArgLevel: PROC [sei: CSEIndex] = { ctx: CTXIndex = ArgCtx[sei]; IF ctx # CTXNull THEN ctxb[ctx].level ← level}; ctx: CTXIndex; bodyNesting ← bodyNesting + 1; IF ~copying THEN DelinkBti[oldBti]; IF ~copying AND (bb[oldBti].level > lL) = (level > lL) THEN { ctx ← bb[oldBti].localCtx; IF ctx # CTXNull THEN ctxb[ctx].level ← level; ioType ← bb[oldBti].ioType; type ← bb[oldBti].type; newBti ← oldBti} ELSE { id: ISEIndex; IF level > lL THEN { newBti ← (dataPtr.table).Words[bodyType, BodyRecord.Callable.Inner.SIZE]; bb[newBti] ← [,,,,,,, Callable[,,,,,,,,,, Inner[frameOffset: ]]]} ELSE { newBti ← (dataPtr.table).Words[bodyType, BodyRecord.Callable.Outer.SIZE]; bb[newBti] ← [,,,,,,, Callable[,,,,,,,,,, Outer[]]]}; IF ~copying THEN { ctx ← bb[oldBti].localCtx; IF ctx # CTXNull THEN ctxb[ctx].level ← level; id ← bb[oldBti].id; ioType ← bb[oldBti].ioType; type ← bb[oldBti].type; bb[newBti].firstSon ← bb[oldBti].firstSon} ELSE { oldCtx: CTXIndex; IF (id ← bb[oldBti].id) # ISENull THEN id ← SearchContext[seb[id].hash, bb[currentEnclosing].localCtx]; ioType ← CopyXferType[bb[oldBti].ioType, NIL]; MapFormals[oldType: bb[oldBti].ioType, newType: ioType]; IF (oldCtx ← bb[oldBti].localCtx) = CTXNull THEN ctx ← CTXNull ELSE { ctx ← NewCtx[level]; ctxb[ctx].seList ← MakeSeChain[ctx, CtxVars[oldCtx], FALSE]; MapIds[oldCtx, ctxb[ctx].seList, 0]}; type ← BodyType[ctx]; bb[newBti].firstSon ← BTNull; dataPtr.nBodies ← dataPtr.nBodies+1; IF level > lL THEN dataPtr.nInnerBodies ← dataPtr.nInnerBodies+1}; bb[newBti].type ← type; bb[newBti].localCtx ← ctx; bb[newBti].info ← bb[oldBti].info; bb[newBti].inline ← bb[oldBti].inline; bb[newBti].resident ← bb[oldBti].resident; bb[newBti].id ← id; bb[newBti].ioType ← ioType; bb[newBti].monitored ← bb[oldBti].monitored; bb[newBti].entry ← bb[oldBti].entry; bb[newBti].internal ← bb[oldBti].internal; bb[newBti].noXfers ← bb[oldBti].noXfers; bb[newBti].hints ← bb[oldBti].hints}; bb[newBti].level ← level; WITH t: seb[ioType] SELECT FROM transfer => {SetArgLevel[t.typeIn]; SetArgLevel[t.typeOut]}; ENDCASE; LinkBti[bti: newBti, parent: currentEnclosing]; currentEnclosing ← newBti}; ExitBody: PROC [node: Tree.Index] = { newBti: CBTIndex = LOOPHOLE[currentEnclosing]; ExitBlock[node]; IF copying THEN UnmapFormals[bb[newBti].ioType]; bodyNesting ← bodyNesting - 1}; EnterCatch: PROC [node: Tree.Index] = { oldBti: CBTIndex = tb[node].info; newBti: CBTIndex; level: ContextLevel = NextLevel[bb[currentEnclosing].level ! StaticNestError => {Log.Error[staticNesting]; RESUME}]; bodyNesting ← bodyNesting + 1; IF ~copying THEN { DelinkBti[oldBti]; newBti ← oldBti; bb[newBti].level ← level} ELSE { newBti ← (dataPtr.table).Words[bodyType, BodyRecord.Callable.Catch.SIZE]; bb[newBti] ← [ link: , firstSon: BTNull, type: RecordSENull, localCtx: CTXNull, level: level, sourceIndex: bb[oldBti].sourceIndex, info: bb[oldBti].info, extension: Callable[ inline: FALSE, id: ISENull, ioType: CSENull, monitored: FALSE, noXfers: bb[oldBti].noXfers, resident: bb[oldBti].resident, entry: FALSE, internal: FALSE, entryIndex: 0, hints: bb[oldBti].hints, closure: Catch[index: ]]]}; FOR bti: BTIndex ← currentEnclosing, ParentBti[bti] UNTIL bti = BTNull DO WITH b: bb[bti] SELECT FROM Callable => {bb[newBti].id ← b.id; EXIT}; ENDCASE; ENDLOOP; LinkBti[bti: newBti, parent: currentEnclosing]; currentEnclosing ← newBti}; ExitCatch: PROC [node: Tree.Index] = { newBti: CBTIndex = LOOPHOLE[currentEnclosing]; ExitBlock[node]; bodyNesting ← bodyNesting - 1}; UpdateBodyNesting: PROC [list: Tree.Link, newBti: BTIndex] = { oldBti: BTIndex = ParentBti[newBti]; UpdateLinks: Tree.Map = { WITH t SELECT FROM subtree => { node: Tree.Index = index; SELECT tb[node].name FROM block => { bti: BTIndex = tb[node].info; IF ParentBti[bti] = oldBti THEN {DelinkBti[bti]; LinkBti[bti, newBti]}; v ← t}; thread => { IF tb[node].info = oldBti THEN tb[node].info ← newBti; tb[node].son[1] ← UpdateLeaves[tb[node].son[1], UpdateLinks]; v ← t}; ENDCASE => v ← UpdateLeaves[t, UpdateLinks]}; ENDCASE => v ← t}; UpdateItem: Tree.Scan = { WITH t SELECT FROM subtree => { node: Tree.Index = index; SELECT tb[node].name FROM assign, extract => tb[node].son[2] ← UpdateLeaves[tb[node].son[2], UpdateLinks]; ENDCASE}; ENDCASE}; ScanList[list, UpdateItem]}; BodyType: PROC [ctx: CTXIndex] RETURNS [rSei: RecordSEIndex] = { rSei ← LOOPHOLE[MakeNonCtxSe[SERecord.cons.record.notLinked.SIZE]]; seb[rSei].typeInfo ← record[ machineDep: FALSE, painted: TRUE, argument: FALSE, hints: [ unifield: FALSE, variant: FALSE, assignable: FALSE, comparable: FALSE, privateFields: TRUE, refField: FALSE, default: FALSE, voidable: FALSE], length: 0, fieldCtx: CTXNull, monitored: FALSE, linkPart: notLinked[]]; seb[rSei].fieldCtx ← ctx; seb[rSei].mark3 ← TRUE; RETURN}; -- id translation AppendSeChain: PROC [ctx: CTXIndex, chain: ISEIndex] = { last, next: ISEIndex; SELECT TRUE FROM chain = ISENull => NULL; (last ← ctxb[ctx].seList) = ISENull => ctxb[ctx].seList ← chain; ENDCASE => { UNTIL (next ← NextSe[last]) = ISENull DO last ← next ENDLOOP; SetSeLink[last, chain]}}; CtxVars: PROC [ctx: CTXIndex] RETURNS [n: CARDINAL ← 0] = { FOR sei: ISEIndex ← FirstCtxSe[ctx], NextSe[sei] UNTIL sei = ISENull DO IF seb[sei].idType # typeTYPE THEN n ← n+1 ENDLOOP; RETURN}; AllocateAList: PROC [ctx: CTXIndex] RETURNS [aLink: AList] = { maxItems: CARDINAL = CtxEntries[ctx]; aLink ← (dataPtr.zone).NEW[ANode[maxItems] ← [next:NIL, ctx:ctx, nItems:0, map:]]}; -- mapping AllocateCopyEntries: PROC [nVars: CARDINAL] RETURNS [seChain: ISEIndex] = { IF nVars = 0 THEN seChain ← ISENull ELSE { IF copyCtx = CTXNull THEN copyCtx ← NewCtx[bb[currentEnclosing].level]; seChain ← MakeSeChain[copyCtx, nVars, TRUE]; AppendSeChain[copyCtx, seChain]}; RETURN}; FillArgSe: PROC [copy, master: ISEIndex] = { CopyArgSe[copy, master]; IF seb[copy].mark4 THEN seb[copy].idValue ← Tree.NullIndex; seb[copy].mark4 ← FALSE; seb[copy].idInfo ← 0}; ExtractArgs: PROC [argType: RecordSEIndex, formalCtx: CTXIndex, node: Tree.Index] RETURNS [nAssigns: CARDINAL] = { aLink: AList = AllocateAList[formalCtx]; nVars: CARDINAL = CtxEntries[formalCtx]; seChain: ISEIndex = AllocateCopyEntries[nVars]; sei1: ISEIndex; sei2: ISEIndex ← seChain; FOR sei1 ← FirstCtxSe[formalCtx], NextSe[sei1] UNTIL sei1 = ISENull DO val: Tree.Link = [symbol[index: sei2]]; FillArgSe[copy: sei2, master: sei1]; PushTree[val]; PushTree[Tree.Null]; PushNode[assign, 2]; SetInfo[dataPtr.textIndex]; IncrCount[sei2]; aLink.map[aLink.nItems] ← [id: sei1, name: FALSE, val: val]; aLink.nItems ← aLink.nItems + 1; sei2 ← NextSe[sei2]; ENDLOOP; IF nVars = 0 THEN nAssigns ← 0 ELSE { PushList[nVars]; PushNode[exlist, 1]; SetInfo[argType]; PushTree[tb[node].son[2]]; tb[node].son[2] ← Tree.Null; PushNode[extract, 2]; SetInfo[dataPtr.textIndex]; nAssigns ← 1}; PushAList[aLink]; RETURN}; MapArgs: PROC [formalCtx: CTXIndex, node: Tree.Index] RETURNS [nAssigns: CARDINAL ← 0] = { aLink: AList = AllocateAList[formalCtx]; nVars: CARDINAL = CountVars[formalCtx, tb[node].son[2]]; seChain: ISEIndex = AllocateCopyEntries[nVars]; sei1, sei2: ISEIndex; MapArg: Tree.Map = { name: BOOL; val: Tree.Link; IF sei1 = ISENull THEN v ← t ELSE { IF MapByName[sei1, t] THEN { name ← TRUE; AdjustForName[t]; val ← t} ELSE { FillArgSe[copy: sei2, master: sei1]; name ← FALSE; val ← [symbol[index: sei2]]; IF t # Tree.Null THEN { PushTree[val]; PushTree[t]; PushNode[assign, 2]; SetInfo[dataPtr.textIndex]; IncrCount[sei2]; nAssigns ← nAssigns + 1}; sei2 ← NextSe[sei2]}; aLink.map[aLink.nItems] ← [id: sei1, name: name, val: val]; aLink.nItems ← aLink.nItems + 1; sei1 ← NextSe[sei1]; v ← Tree.Null}; RETURN}; sei1 ← FirstCtxSe[formalCtx]; sei2 ← seChain; tb[node].son[2] ← UpdateList[tb[node].son[2], MapArg]; PushAList[aLink]; RETURN}; MapIds: PROC [ctx: CTXIndex, chain: ISEIndex, nRefs: [0..1]] = { aLink: AList = AllocateAList[ctx]; sei1: ISEIndex ← FirstCtxSe[ctx]; sei2: ISEIndex ← chain; UNTIL sei1 = ISENull DO IF seb[sei1].idType # typeTYPE THEN { CopyArgSe[sei2, sei1]; IF seb[sei2].mark4 THEN seb[sei2].idValue ← Tree.NullIndex; seb[sei2].idInfo ← nRefs; aLink.map[aLink.nItems] ← [id: sei1, name: FALSE, val: [symbol[index:sei2]]]; aLink.nItems ← aLink.nItems + 1; sei2 ← NextSe[sei2]}; sei1 ← NextSe[sei1]; ENDLOOP; PushAList[aLink]}; UnmapIds: PROC [decl: {implicit, explicit}] = { aLink: AList ← PopAList[]; FOR i: CARDINAL IN [0..aLink.nItems) DO WITH aLink.map[i].val SELECT FROM symbol => IF decl = implicit AND ~aLink.map[i].name THEN seb[index].mark4 ← TRUE; ENDCASE; aLink.map[i].val ← DiscardTree[aLink.map[i].val]; ENDLOOP; (dataPtr.zone).FREE[@aLink]}; MapFields: PROC [oldRecord, newRecord: CSEIndex, nRefs: [0..1]] = { oldCtx: CTXIndex = ArgCtx[oldRecord]; IF oldCtx # CTXNull THEN { aLink: AList = AllocateAList[oldCtx]; sei1: ISEIndex ← FirstCtxSe[oldCtx]; sei2: ISEIndex ← FirstCtxSe[ArgCtx[newRecord]]; UNTIL sei1 = ISENull DO seb[sei2].idInfo ← nRefs; aLink.map[aLink.nItems] ← [id: sei1, name: FALSE, val: [symbol[index:sei2]]]; aLink.nItems ← aLink.nItems + 1; sei1 ← NextSe[sei1]; sei2 ← NextSe[sei2]; ENDLOOP; PushAList[aLink]}}; MapFormals: PROC [oldType, newType: CSEIndex] = { WITH new: seb[newType] SELECT FROM transfer => WITH old: seb[oldType] SELECT FROM transfer => { MapFields[old.typeIn, new.typeIn, 1]; MapFields[old.typeOut, new.typeOut, 0]}; ENDCASE => ERROR; ENDCASE}; UnmapFormals: PROC [type: CSEIndex] = { WITH t: seb[type] SELECT FROM transfer => { IF ArgCtx[t.typeOut] # CTXNull THEN UnmapIds[implicit]; IF ArgCtx[t.typeIn] # CTXNull THEN UnmapIds[implicit]}; ENDCASE}; -- reference count adjustment CountedSei: PROC [sei: ISEIndex] RETURNS [BOOL] = { ctx: CTXIndex = seb[sei].idCtx; RETURN [~seb[sei].constant AND ctxb[ctx].level # lZ AND ctxb[ctx].ctxType # included]}; IncrCount: PROC [sei: ISEIndex] = { -- modified BumpCount (Pass3I) IF seb[sei].idType # typeTYPE AND (~seb[sei].mark4 OR CountedSei[sei]) THEN seb[sei].idInfo ← seb[sei].idInfo + 1}; DecrCount: PROC [sei: ISEIndex] = { IF seb[sei].idType # typeTYPE AND (~seb[sei].mark4 OR CountedSei[sei]) THEN IF seb[sei].idInfo # 0 THEN seb[sei].idInfo ← seb[sei].idInfo - 1}; AdjustForName: Tree.Scan = { WITH t SELECT FROM symbol => DecrCount[index]; subtree => { node: Tree.Index = index; SELECT tb[node].name FROM thread => AdjustForName[tb[node].son[1]]; ENDCASE => ScanSons[t, AdjustForName]}; ENDCASE}; SetCtxCounts: PROC [ctx: CTXIndex, nRefs: [0..1]] = { FOR sei: ISEIndex ← FirstCtxSe[ctx], NextSe[sei] UNTIL sei = ISENull DO IF ~seb[sei].constant THEN seb[sei].idInfo ← nRefs; ENDLOOP}; BumpCtxCounts: PROC [ctx: CTXIndex, incr: CARDINAL] = { FOR sei: ISEIndex ← FirstCtxSe[ctx], NextSe[sei] UNTIL sei = ISENull DO IF ~seb[sei].constant THEN seb[sei].idInfo ← seb[sei].idInfo + incr; ENDLOOP}; ComputeArgCounts: PROC [type: CSEIndex, body: Tree.Link] = { typeIn, typeOut: RecordSEIndex; argCtx, resultCtx: CTXIndex; [typeIn, typeOut] ← TransferTypes[type]; argCtx ← FieldCtx[typeIn]; resultCtx ← FieldCtx[typeOut]; IF argCtx # CTXNull OR resultCtx # CTXNull THEN { UpdateCount: Tree.Scan = { WITH t SELECT FROM symbol => { sei: ISEIndex = index; SELECT seb[sei].idCtx FROM CTXNull => NULL; argCtx, resultCtx => seb[sei].idInfo ← seb[sei].idInfo + 1; ENDCASE}; subtree => { node: Tree.Index = index; IF tb[node].name = return AND tb[node].son[1] = Tree.Null THEN BumpCtxCounts[resultCtx, 1]; ScanSons[t, UpdateCount]}; ENDCASE => NULL}; SetCtxCounts[argCtx, 1]; SetCtxCounts[resultCtx, 0]; ScanSons[body, UpdateCount]}}; FieldCtx: PROC [rSei: RecordSEIndex] RETURNS [CTXIndex] = { RETURN [IF rSei = RecordSENull THEN CTXNull ELSE seb[rSei].fieldCtx]}; -- association lists PushAList: PROC [aLink: AList] = {aLink.next ← aStack; aStack ← aLink}; PopAList: PROC RETURNS [aLink: AList] = { IF aStack = NIL THEN ERROR; aLink ← aStack; aStack ← aLink.next}; ExpandSei: PROC [sei: ISEIndex] RETURNS [v: Tree.Link] = { i: CARDINAL; FOR aLink: AList ← aStack, aLink.next UNTIL aLink = NIL DO IF seb[sei].idCtx = aLink.ctx THEN FOR i IN [0 .. aLink.nItems) DO IF aLink.map[i].id = sei THEN GO TO Found ENDLOOP; REPEAT Found => { saveCopying: BOOL = copying; copying ← TRUE; v ← ExpandTree[aLink.map[i].val]; copying ← saveCopying}; FINISHED => {IF copying THEN IncrCount[sei]; v ← [symbol[index:sei]]}; ENDLOOP; RETURN}; -- nested calls ThreadSubst: PROC [node: Tree.Index, dest: Tree.Link] = { dThread: Tree.Index = GetNode[NthSon[dest, 1]]; IF copying THEN { sThread: Tree.Index; DO sThread ← GetNode[tb[node].son[1]]; IF tb[sThread].name # thread THEN ERROR; IF tb[sThread].son[2] = Tree.Null THEN EXIT; node ← GetNode[tb[sThread].son[2]]; ENDLOOP; tb[dThread].son[2] ← Tree.Null; tb[sThread].son[2] ← dest; MarkShared[dest, TRUE]}; tb[dThread].info ← currentEnclosing}; }.