DIRECTORY A3: TYPE USING [ Bundling, CanonicalType, DefaultInit, LongPath, NewableType, OperandInternal, OperandLhs, OperandType, TypeForTree, Unbundle, Voidable], Alloc: TYPE USING [Notifier, Top], ComData: TYPE USING [ bodyIndex, idUNWIND, ownSymbols, seAnon, stopping, table, textIndex, typeCONDITION, typeListANY, typeLOCK], ConvertUnsafe: TYPE USING [SubString], Log: TYPE USING [Error, ErrorSei, ErrorTree], Pass3: TYPE USING [lockNode], P3: TYPE USING [ Attr, fullAttr, NPUse, Safety, TextForm, pathNP, phraseNP, BoundNP, MergeNP, SequenceNP, SetNP, And, Apply, BindTree, BumpArgRefs, CheckLocals, CheckScope, ClearRefStack, CopyTree, EnterType, EnterComposite, Exp, FirstId, InitialExp, MakeLongType, MakeRefType, MatchFields, PopCtx, PushCtx, RAttr, Rhs, RPop, RPush, RType, SafetyAttr, SetSafety, SealRefStack, SearchCtxList, Stmt, TypeAppl, UnsealRefStack, UpdateTreeAttr, VoidExp], P3S: TYPE USING [BodyData, continued, currentBody, markCatch, safety], Symbols: TYPE USING [ Base, HTIndex, SERecord, SEIndex, ISEIndex, CSEIndex, RecordSEIndex, RefSEIndex, CTXIndex, BodyRecord, BTIndex, CBTIndex, HTNull, SENull, ISENull, CSENull, RecordSENull, CTXNull, CBTNull, lG, lZ, RootBti, typeANY, seType, ctxType, mdType, bodyType], SymbolOps: TYPE USING [ ArgCtx, ArgRecord, EnterString, FindString, FirstCtxSe, MakeNonCtxSe, NextSe, NormalType, ReferentType, TransferTypes, TypeRoot, UnderType], Tree: TYPE USING [Base, Index, Link, Map, NodeName, Null, NullIndex, Scan, treeType], TreeOps: TYPE USING [ FreeNode, FreeTree, GetNode, ListLength, MakeList, MakeNode, NthSon, PopTree, PushList, PushTree, PushSe, PushNode, OpName, ReverseUpdateList, ScanList, SetAttr, SetInfo, UpdateList], Types: TYPE USING [Assignable, Equivalent]; Pass3M: PROGRAM IMPORTS A3, Alloc, Log, P3, P3S, SymbolOps, TreeOps, Types, dataPtr: ComData, passPtr: Pass3 EXPORTS P3 = { OPEN SymbolOps, Symbols, A3, P3, TreeOps; InsertCatchLabel: PUBLIC SIGNAL [catchSeen, exit: BOOL] = CODE; tb: Tree.Base; -- tree base address (local copy) seb: Symbols.Base; -- se table base address (local copy) ctxb: Symbols.Base; -- context table base (local copy) mdb: Symbols.Base; -- module table base (local copy) bb: Symbols.Base; -- body table base (local copy) MiscNotify: PUBLIC Alloc.Notifier = { tb _ base[Tree.treeType]; seb _ base[seType]; ctxb _ base[ctxType]; mdb _ base[mdType]; bb _ base[bodyType]}; current: POINTER TO P3S.BodyData = @P3S.currentBody; MiscStmt: PUBLIC PROC [node: Tree.Index] RETURNS [val: Tree.Link] = { val _ [subtree[index: node]]; -- the default SELECT tb[node].name FROM signal, error, start, join, wait => { PushTree[SELECT tb[node].name FROM start => Start[node], join => Join[node], wait => Wait[node], ENDCASE => Signal[node]]; SELECT RType[] FROM CSENull, typeANY => NULL; ENDCASE => Log.Error[nonVoidStmt]; SetInfo[dataPtr.textIndex]; val _ PopTree[]; RPop[]; pathNP _ SequenceNP[pathNP][phraseNP]; IF OpName[val] = error THEN current.reachable _ FALSE}; xerror => { subNode: Tree.Index; IF current.catchDepth # 0 THEN Log.Error[misplacedReturn]; tb[node].name _ error; val _ MiscStmt[node]; subNode _ GetNode[val]; IF tb[subNode].attr1 THEN Log.ErrorTree[typeClash, val]; SELECT tb[subNode].name FROM error, errorx => tb[subNode].name _ xerror; ENDCASE => NULL; tb[subNode].attr1 _ current.entry; tb[subNode].attr3 _ FALSE; IF current.entry THEN tb[subNode].attr2 _ CheckLocals[tb[subNode].son[2]]; IF tb[subNode].nSons > 2 THEN Log.Error[misplacedCatch]; current.reachable _ FALSE}; resume => Resume[node]; reject => { IF current.catchDepth = 0 THEN Log.Error[misplacedResume]; current.reachable _ FALSE}; continue, retry => { SIGNAL InsertCatchLabel[catchSeen:FALSE, exit:tb[node].name=continue]; current.reachable _ FALSE}; restart => {val _ Restart[node]; pathNP _ SequenceNP[pathNP][phraseNP]}; stop => { IF dataPtr.bodyIndex # RootBti OR current.catchDepth # 0 OR current.returnRecord # SENull THEN Log.Error[misplacedStop]; dataPtr.stopping _ TRUE; pathNP _ SetNP[pathNP]}; notify, broadcast => { OPEN tb[node]; type: CSEIndex; IF ~current.lockHeld THEN Log.Error[misplacedMonitorRef]; son[1] _ Exp[son[1], typeANY]; IF OperandLhs[son[1]] = none THEN Log.ErrorTree[nonLHS, son[1]]; type _ RType[]; RPop[]; pathNP _ SequenceNP[pathNP][phraseNP]; IF type # dataPtr.typeCONDITION THEN Log.ErrorTree[typeClash, son[1]]}; free => { OPEN tb[node]; type, subType: CSEIndex; long, counted: BOOL; [v:son[1], long:long, counted:counted] _ EvalZone[son[1]]; RPop[]; son[2] _ Exp[son[2], typeANY]; type _ RType[]; RPop[]; subType _ NormalType[type]; WITH s: seb[subType] SELECT FROM ref => { IF s.readOnly THEN Log.ErrorTree[nonLHS, son[2]]; type _ UnderType[s.refType]; IF long # (seb[type].typeTag = long) THEN GO TO fail; type _ NormalType[type]; WITH t: seb[type] SELECT FROM ref => IF t.counted # counted THEN GO TO fail; ENDCASE => GO TO fail; IF P3S.safety = checked AND ~counted THEN Log.ErrorTree[unsafeOperation, [subtree[node]]]; EXITS fail => Log.ErrorTree[typeClash, son[2]]}; ENDCASE => Log.ErrorTree[typeClash, son[2]]; IF nSons > 3 THEN { saveNP: NPUse = phraseNP; [] _ CatchPhrase[son[4]]; phraseNP _ MergeNP[saveNP][phraseNP]}; attr2 _ long; attr3 _ counted; SELECT TRUE FROM ~counted => attr1 _ FALSE; (OpName[son[2]] # addr) => {Log.ErrorTree[other, son[2]]; attr1 _ FALSE}; ENDCASE => attr1 _ OperandLhs[NthSon[son[2], 1]] = counted}; dst, lst, lste, lstf => { OPEN tb[node]; v: Tree.Link; v _ son[1] _ Exp[son[1], typeANY]; RPop[]; SELECT name FROM dst => IF OperandLhs[son[1]] = none THEN GO TO fail; lst => NULL; lste => current.noXfers _ FALSE; lstf => current.reachable _ FALSE; ENDCASE; IF name = lste OR name = lstf THEN phraseNP _ SetNP[phraseNP]; pathNP _ SequenceNP[pathNP][phraseNP]; DO WITH v SELECT FROM symbol => IF seb[index].constant THEN GO TO fail ELSE EXIT; subtree => { IF tb[index].name # dollar THEN GO TO fail; v _ tb[index].son[1]}; ENDCASE => GO TO fail; ENDLOOP; IF P3S.safety = checked THEN Log.ErrorTree[unsafeOperation, [subtree[node]]]; EXITS fail => Log.ErrorTree[nonLHS, tb[node].son[1]]}; enable => { OPEN tb[node]; saveEnabled: BOOL = current.unwindEnabled; IF CatchPhrase[son[1]].unwindCaught THEN current.unwindEnabled _ TRUE; IF phraseNP # none THEN pathNP _ unsafe; son[2] _ UpdateList[son[2], Stmt]; attr3 _ FALSE; current.unwindEnabled _ saveEnabled}; ENDCASE => Log.Error[unimplemented]; RETURN}; New: PROC [node: Tree.Index, target: CSEIndex] RETURNS [Tree.Link] = { OPEN tb[node]; pType: RefSEIndex; subType, rootType: SEIndex; attr: Attr; saveNP: NPUse; long, counted: BOOL; [v:son[1], long:long, counted:counted] _ EvalZone[son[1]]; attr _ RAttr[]; RPop[]; saveNP _ phraseNP; current.noXfers _ attr.noXfer _ FALSE; attr.const _ FALSE; son[2] _ TypeAppl[son[2]]; attr _ And[attr, RAttr[]]; saveNP _ MergeNP[saveNP][phraseNP]; RPop[]; subType _ TypeForTree[son[2]]; rootType _ TypeRoot[subType]; IF ~NewableType[subType] THEN Log.ErrorTree[typeLength, son[2]]; IF counted THEN EnterType[rootType, FALSE]; IF son[3] = Tree.Null THEN son[3] _ DefaultInit[subType] ELSE { StringInit: PROC [t: Tree.Link] RETURNS [BOOL] = INLINE { RETURN [SELECT OpName[t] FROM stringinit => TRUE, lengthen => (OpName[NthSon[t, 1]] = stringinit), ENDCASE => FALSE]}; extFlag: BOOL; [son[3], extFlag] _ InitialExp[son[3], subType]; SELECT TRUE FROM extFlag => Log.ErrorTree[misusedInline, son[3]]; StringInit[son[3]] => Log.ErrorTree[defaultForm, son[3]]; ENDCASE}; attr _ And[attr, RAttr[]]; phraseNP _ SequenceNP[saveNP][phraseNP]; RPop[]; pType _ MakeRefType[ cType: subType, readOnly: tb[node].attr1, counted: counted, hint: NormalType[target]]; IF counted AND son[3] # Tree.Null THEN EnterComposite[UnderType[subType], son[3], TRUE]; IF son[3] = Tree.Null AND ~Voidable[subType] THEN Log.ErrorTree[missingInit, [subtree[node]]]; IF nSons > 3 THEN { saveNP: NPUse = phraseNP; [] _ CatchPhrase[son[4]]; phraseNP _ MergeNP[saveNP][phraseNP]}; attr2 _ long; attr3 _ counted; RPush[IF long THEN MakeLongType[pType, target] ELSE pType, attr]; RETURN [[subtree[index: node]]]}; EvalZone: PROC [t: Tree.Link] RETURNS [v: Tree.Link, long, counted: BOOL] = { type, nType: CSEIndex; nDerefs: CARDINAL; long _ counted _ TRUE; IF t = Tree.Null THEN {v _ Tree.Null; RPush[typeANY, fullAttr]} ELSE { v _ Exp[t, typeANY]; type _ RType[]; nDerefs _ 0; DO nType _ NormalType[type]; WITH s: seb[nType] SELECT FROM zone => {long _ ~s.mds; counted _ s.counted; GO TO success}; ref => { IF (nDerefs _ nDerefs + 1) > 63 THEN GO TO failure; PushTree[v]; PushNode[uparrow, 1]; SetAttr[2, seb[type].typeTag = long]; type _ UnderType[s.refType]; SetInfo[type]; v _ PopTree[]}; record => IF Bundling[nType] # 0 THEN type _ Unbundle[LOOPHOLE[nType, RecordSEIndex]] ELSE GO TO failure; ENDCASE => GO TO failure; REPEAT success => NULL; failure => Log.ErrorTree[typeClash, v]; ENDLOOP}; RETURN}; Cons: PROC [node: Tree.Index, target: CSEIndex] RETURNS [Tree.Link] = { nType: CSEIndex = NodeType[target, [subtree[node]]]; PushTree[tb[node].son[1]]; tb[node].son[1] _ Tree.Null; PushNode[implicitTC, 0]; SetInfo[nType]; PushTree[tb[node].son[2]]; tb[node].son[2] _ Tree.Null; PushTree[Tree.Null]; PushNode[apply, -2]; SetAttr[1, FALSE]; IF tb[node].nSons > 2 THEN { PushTree[tb[node].son[3]]; tb[node].son[3] _ Tree.Null; PushNode[new, 4]} ELSE PushNode[new, 3]; FreeNode[node]; RETURN [Exp[PopTree[], target]]}; ListCons: PROC [node: Tree.Index, target: CSEIndex] RETURNS [Tree.Link] = { nType: CSEIndex = NodeType[target, [subtree[node]]]; n: CARDINAL = ListLength[tb[node].son[2]]; k: CARDINAL _ n; list, zone: Tree.Link; ListItem: Tree.Map = { PushTree[IF (k_k-1) = 0 THEN zone ELSE P3.CopyTree[zone]]; PushNode[implicitTC, 0]; SetInfo[nType]; PushTree[t]; PushTree[list]; PushList[2]; PushTree[Tree.Null]; PushNode[apply, -2]; SetAttr[1, FALSE]; list _ MakeNode[new, 3]; RETURN [Tree.Null]}; PushTree[Tree.Null]; list _ MakeNode[nil, 1]; IF n = 0 THEN [v: tb[node].son[1]] _ EvalZone[tb[node].son[1]] ELSE { zone _ tb[node].son[1]; tb[node].son[1] _ Tree.Null; tb[node].son[2] _ ReverseUpdateList[tb[node].son[2], ListItem]}; FreeNode[node]; RETURN [Exp[list, target]]}; NodeType: PROC [target: CSEIndex, t: Tree.Link] RETURNS [nType: CSEIndex] = { subType: CSEIndex = NormalType[target]; WITH r: seb[subType] SELECT FROM ref => { rType: CSEIndex = UnderType[r.refType]; IF ~r.list AND (seb[rType].typeTag = any OR rType = typeANY) THEN nType _ ReferentType[dataPtr.typeListANY] ELSE { IF ~r.list THEN Log.ErrorTree[typeClash, t]; nType _ rType}}; ENDCASE => IF subType = typeANY THEN nType _ ReferentType[dataPtr.typeListANY] ELSE {Log.ErrorTree[typeClash, t]; nType _ typeANY}; RETURN}; MiscXfer: PUBLIC PROC [node: Tree.Index, target: CSEIndex] RETURNS [val: Tree.Link] = { SELECT tb[node].name FROM new => val _ New[node, target]; signalx, errorx => val _ Signal[node]; create => val _ Create[node, target]; startx => val _ Start[node]; fork => val _ Fork[node, target]; joinx => val _ Join[node]; cons => val _ Cons[node, target]; listcons => val _ ListCons[node, target]; ENDCASE => {Log.Error[unimplemented]; val _ [subtree[node]]}; RETURN}; MakeFrameRecord: PUBLIC PROC [t: Tree.Link] RETURNS [rSei: CSEIndex] = { bti: CBTIndex = XferBody[t]; IF bti # CBTNull THEN { argType: SEIndex = TransferTypes[bb[bti].ioType].typeIn; rSei _ IF bb[bti].type # RecordSENull AND argType = SENull THEN bb[bti].type ELSE AllocFrameRecord[bti, argType]} ELSE {Log.Error[nonTypeCons]; rSei _ typeANY}; RETURN}; AllocFrameRecord: PROC [bti: CBTIndex, link: SEIndex] RETURNS [sei: RecordSEIndex] = { sei _ LOOPHOLE[MakeNonCtxSe[SERecord.cons.record.linked.SIZE]]; seb[sei] _ SERecord[mark3: TRUE, mark4: FALSE, body: cons[record[ machineDep: FALSE, painted: TRUE, argument: FALSE, hints: [ unifield: FALSE, variant: FALSE, assignable: FALSE, comparable: FALSE, privateFields: TRUE, refField: TRUE, default: FALSE, voidable: FALSE], fieldCtx: bb[bti].localCtx, length: IF bb[bti].type # RecordSENull THEN seb[bb[bti].type].length ELSE 0, monitored: bb[bti].monitored, linkPart: linked[link]]]]; RETURN}; XferBody: PROC [t: Tree.Link] RETURNS [bti: CBTIndex] = { sei: ISEIndex; type: CSEIndex; WITH t SELECT FROM symbol => { sei _ index; type _ UnderType[seb[sei].idType]; bti _ WITH seb[type] SELECT FROM transfer => IF ~seb[sei].immutable THEN CBTNull ELSE SELECT mode FROM program => IF seb[sei].mark4 THEN (IF seb[sei].constant THEN seb[sei].idInfo ELSE CBTNull) ELSE RootBti, proc => IF sei = bb[dataPtr.bodyIndex].id THEN dataPtr.bodyIndex ELSE CBTNull, ENDCASE => CBTNull, ENDCASE => CBTNull}; ENDCASE => bti _ CBTNull; RETURN}; XferForFrame: PUBLIC PROC [ctx: CTXIndex] RETURNS [type: CSEIndex _ CSENull] = { bti: BTIndex _ BTIndex.FIRST; btLimit: BTIndex = (dataPtr.table).Top[bodyType]; UNTIL bti = btLimit DO WITH entry: bb[bti] SELECT FROM Callable => { IF entry.localCtx = ctx THEN RETURN [UnderType[entry.ioType]]; bti _ bti + (WITH entry SELECT FROM Inner => BodyRecord.Callable.Inner.SIZE, Catch => BodyRecord.Callable.Catch.SIZE, ENDCASE => BodyRecord.Callable.Outer.SIZE)}; ENDCASE => bti _ bti + BodyRecord.Other.SIZE; ENDLOOP; RETURN [CSENull]}; Create: PROC [node: Tree.Index, target: CSEIndex] RETURNS [val: Tree.Link] = { subNode: Tree.Index; val _ ForceApplication[tb[node].son[1]]; tb[node].son[1] _ Tree.Null; FreeNode[node]; subNode _ GetNode[val]; BEGIN OPEN tb[subNode]; type, mType, rType: CSEIndex; attr: Attr; CreateError: PROC = {Log.ErrorTree[typeClash, son[1]]; type _ typeANY}; name _ create; attr1 _ TRUE; son[1] _ Exp[son[1], typeANY]; mType _ RType[]; attr _ RAttr[]; RPop[]; phraseNP _ SetNP[phraseNP]; WITH seb[mType] SELECT FROM transfer => IF mode = program THEN SELECT XferBody[son[1]] FROM CBTNull => type _ mType; RootBti => { type _ IF seb[target].typeTag = ref THEN MakeRefType[MakeFrameRecord[son[1]], target] ELSE mType; attr1 _ FALSE}; ENDCASE => CreateError[] ELSE CreateError[]; ref => { type _ mType; rType _ UnderType[refType]; WITH seb[rType] SELECT FROM record => SELECT TRUE FROM (ctxb[fieldCtx].level # lG) => CreateError[]; (seb[target].typeTag = transfer) => { type _ XferForFrame[fieldCtx]; IF type = CSENull THEN {Log.Error[unimplemented]; type _ typeANY}}; ENDCASE; ENDCASE => IF refType # typeANY THEN CreateError[]}; ENDCASE => IF mType = typeANY THEN type _ typeANY ELSE CreateError[]; IF son[2] # Tree.Null THEN { Log.ErrorTree[noApplication, son[1]]; son[2] _ UpdateList[son[2], VoidExp]}; IF nSons > 2 THEN [] _ CatchPhrase[son[3]]; current.noXfers _ attr.noXfer _ FALSE; attr.const _ FALSE; RPush[type, attr]; END; RETURN}; Start: PROC [node: Tree.Index] RETURNS [Tree.Link] = { subNode: Tree.Index; subNode _ Apply[GetNode[ForceApplication[tb[node].son[1]]], typeANY, TRUE]; SELECT tb[subNode].name FROM start, startx, apply => NULL; ENDCASE => Log.ErrorTree[typeClash, tb[subNode].son[1]]; tb[node].son[1] _ Tree.Null; FreeNode[node]; RETURN [[subtree[subNode]]]}; Restart: PROC [node: Tree.Index] RETURNS [val: Tree.Link] = { subNode: Tree.Index; type: CSEIndex; val _ ForceApplication[tb[node].son[1]]; subNode _ GetNode[val]; BEGIN OPEN tb[subNode]; name _ tb[node].name; info _ tb[node].info; son[1] _ Exp[son[1], typeANY]; type _ RType[]; RPop[]; phraseNP _ SetNP[phraseNP]; WITH seb[type] SELECT FROM ref => NULL; -- a weak check for now transfer => IF mode # program OR XferBody[son[1]] # CBTNull THEN Log.ErrorTree[typeClash, son[1]]; ENDCASE => IF type # typeANY THEN Log.ErrorTree[typeClash, son[1]]; IF son[2] # Tree.Null THEN { Log.ErrorTree[noApplication, son[1]]; son[2] _ UpdateList[son[2], VoidExp]}; IF nSons > 2 THEN [] _ CatchPhrase[son[3]]; END; current.noXfers _ FALSE; tb[node].son[1] _ Tree.Null; FreeNode[node]; RETURN}; Fork: PROC [node: Tree.Index, target: CSEIndex] RETURNS [Tree.Link] = { subNode: Tree.Index; type: CSEIndex; attr: Attr; t: Tree.Link _ ForceApplication[tb[node].son[1]]; tb[node].son[1] _ Tree.Null; FreeNode[node]; subNode _ Apply[GetNode[t], typeANY, TRUE]; attr _ RAttr[]; RPop[]; SELECT tb[subNode].name FROM call, callx => { s: Tree.Link _ tb[subNode].son[1]; subType: CSEIndex; IF OpName[s] = thread THEN { s _ NthSon[s, 1]; Log.ErrorTree[misusedInline, s]}; IF current.lockHeld AND OperandInternal[s] THEN Log.ErrorTree[internalCall, s]; subType _ OperandType[s]; WITH procType: seb[subType] SELECT FROM transfer => { type _ MakeNonCtxSe[SERecord.cons.transfer.SIZE]; seb[type] _ SERecord[mark3: TRUE, mark4: TRUE, body: cons[transfer[ mode: process, safe: procType.safe, typeIn: RecordSENull, typeOut: procType.typeOut]]]; IF P3S.safety = checked THEN { CheckArg: Tree.Map = { argType: CSEIndex = OperandType[t]; subType: CSEIndex = NormalType[argType]; WITH s: seb[subType] SELECT FROM ref => {IF s.var THEN Log.ErrorTree[unsafeOperation, t]; v _ t}; transfer => v _ CheckScope[t, argType]; ENDCASE => v _ t; RETURN}; tb[subNode].son[1] _ CheckScope[s, subType]; tb[subNode].son[2] _ UpdateList[tb[subNode].son[2], CheckArg]}}; ENDCASE => ERROR; tb[subNode].name _ fork}; apply => type _ typeANY; ENDCASE => {Log.ErrorTree[typeClash, tb[node].son[1]]; type _ typeANY}; tb[subNode].info _ type; RPush[type, attr]; RETURN [[subtree[subNode]]]}; Join: PROC [node: Tree.Index] RETURNS [Tree.Link] = { subNode: Tree.Index; subNode _ Apply[GetNode[ForceApplication[tb[node].son[1]]], typeANY, TRUE]; SELECT tb[subNode].name FROM join, joinx => NULL; apply => NULL; ENDCASE => Log.ErrorTree[typeClash, tb[subNode].son[1]]; tb[node].son[1] _ Tree.Null; FreeNode[node]; RETURN [[subtree[subNode]]]}; Wait: PROC [node: Tree.Index] RETURNS [val: Tree.Link] = { subNode: Tree.Index; saveNP: NPUse; IF ~current.lockHeld THEN Log.Error[misplacedMonitorRef]; subNode _ Apply[GetNode[ForceApplication[tb[node].son[1]]], typeANY, TRUE]; SELECT tb[subNode].name FROM wait => NULL; apply => NULL; ENDCASE => Log.ErrorTree[typeClash, tb[subNode].son[1]]; tb[node].son[1] _ Tree.Null; FreeNode[node]; IF OperandLhs[tb[subNode].son[1]] = none THEN Log.ErrorTree[nonLHS, tb[subNode].son[1]]; [] _ FreeTree[tb[subNode].son[2]]; saveNP _ phraseNP; tb[subNode].son[2] _ tb[subNode].son[1]; tb[subNode].son[1] _ CopyLock[]; phraseNP _ MergeNP[saveNP][phraseNP]; RETURN [[subtree[subNode]]]}; LockVar: PUBLIC PROC [t: Tree.Link] RETURNS [val: Tree.Link] = { type, nType: CSEIndex; desc: ConvertUnsafe.SubString; sei: ISEIndex; nDerefs: CARDINAL; long, b: BOOL; Dereference: PROC [type: CSEIndex] = { PushTree[val]; PushNode[uparrow, 1]; SetInfo[type]; SetAttr[2, long]; val _ PopTree[]}; val _ Exp[t, typeANY]; long _ LongPath[val]; type _ RType[]; RPop[]; nDerefs _ 0; DO IF type = dataPtr.typeLOCK THEN {IF nDerefs # 0 THEN Dereference[type]; GO TO success}; type _ UnderType[TypeRoot[type]]; nType _ NormalType[type]; WITH seb[nType] SELECT FROM record => { IF monitored THEN { desc _ ["LOCK"L, 0, ("LOCK"L).length]; [b, sei] _ SearchCtxList[EnterString[desc], fieldCtx]; IF ~b THEN {Log.Error[noAccess]; sei _ dataPtr.seAnon}; PushTree[val]; PushSe[sei]; PushNode[IF nDerefs = 0 THEN dollar ELSE dot, 2]; SetInfo[dataPtr.typeLOCK]; SetAttr[2, long]; val _ PopTree[]; GO TO success}; GO TO failure}; ref => { IF (nDerefs _ nDerefs + 1) > 63 THEN GO TO failure; long _ seb[type].typeTag = long; IF nDerefs > 1 THEN Dereference[type]; type _ UnderType[refType]}; ENDCASE => GO TO failure; REPEAT success => NULL; failure => Log.ErrorTree[typeClash, val]; ENDLOOP; IF OperandLhs[val] = none THEN Log.ErrorTree[nonLHS, val]; RETURN}; FindLockParams: PUBLIC PROC RETURNS [formal, actual: ISEIndex] = { node: Tree.Index = GetNode[tb[passPtr.lockNode].son[1]]; found: BOOL; IF node = Tree.NullIndex THEN formal _ actual _ ISENull ELSE { formal _ FirstId[node]; IF current.inputRecord = SENull THEN found _ FALSE ELSE [found, actual] _ SearchCtxList[ seb[formal].hash, seb[current.inputRecord].fieldCtx]; IF ~found THEN actual _ ISENull}; RETURN}; LambdaApply: PROC [t: Tree.Link, formal, actual: ISEIndex] RETURNS [v: Tree.Link] = { BindFormal: PROC [sei: ISEIndex] RETURNS [Tree.Link] = { RETURN [[symbol[index: IF sei = formal THEN actual ELSE sei]]]}; v _ BindTree[t, BindFormal]; [] _ UpdateTreeAttr[v]; RETURN}; CopyLock: PUBLIC PROC RETURNS [val: Tree.Link] = { formal, actual: ISEIndex; SELECT TRUE FROM passPtr.lockNode = Tree.NullIndex => val _ Tree.Null; tb[current.bodyNode].son[4] # Tree.Null => val _ LambdaApply[tb[current.bodyNode].son[4], ISENull, ISENull]; ENDCASE => { [formal:formal, actual:actual] _ FindLockParams[]; IF formal # SENull THEN { IF actual = SENull THEN {Log.ErrorSei[missingLock, formal]; actual _ dataPtr.seAnon}; IF ~Types.Assignable[ [dataPtr.ownSymbols, UnderType[seb[formal].idType]], [dataPtr.ownSymbols, UnderType[seb[actual].idType]]] THEN Log.ErrorSei[typeClash, actual]}; val _ LambdaApply[tb[passPtr.lockNode].son[2], formal, actual]}; RETURN}; Signal: PUBLIC PROC [node: Tree.Index] RETURNS [val: Tree.Link] = { subNode: Tree.Index; nodeTag: Tree.NodeName = tb[node].name; subNode _ Apply[GetNode[ForceApplication[tb[node].son[1]]], typeANY, TRUE]; SELECT tb[subNode].name FROM signal, signalx => tb[subNode].name _ nodeTag; error, errorx => { SELECT nodeTag FROM signal, signalx => Log.ErrorTree[typeClash, tb[subNode].son[1]]; ENDCASE => NULL; tb[subNode].name _ nodeTag}; apply => NULL; ENDCASE => Log.ErrorTree[typeClash, tb[subNode].son[1]]; tb[node].son[1] _ Tree.Null; FreeNode[node]; RETURN [[subtree[subNode]]]}; ForceApplication: PROC [t: Tree.Link] RETURNS [Tree.Link] = { IF OpName[t] = apply THEN RETURN [t]; PushTree[t]; PushTree[Tree.Null]; RETURN [MakeNode[apply, 2]]}; CatchPhrase: PUBLIC PROC [t: Tree.Link] RETURNS [unwindCaught: BOOL] = { saveReachable: BOOL = current.reachable; savePathNP: NPUse = pathNP; saveSafety: Safety = P3S.safety; enclosingSafe: BOOL = (saveSafety = checked); entryNP, exitNP: NPUse; CatchItem: Tree.Scan = { node: Tree.Index = GetNode[t]; type: CSEIndex _ typeANY; mixed, safe, error: BOOL _ FALSE; saveIndex: CARDINAL = dataPtr.textIndex; CatchLabel: Tree.Map = { subType: CSEIndex; v _ Exp[t, typeANY]; subType _ CanonicalType[RType[]]; RPop[]; entryNP _ SequenceNP[entryNP][phraseNP]; WITH t: seb[subType] SELECT FROM transfer => IF t.mode = signal OR t.mode = error THEN { IF type = typeANY THEN type _ subType ELSE IF ~Types.Equivalent[ [dataPtr.ownSymbols, type], [dataPtr.ownSymbols, subType]] THEN mixed _ TRUE; IF t.safe THEN safe _ TRUE; IF t.mode = error THEN error _ TRUE} ELSE Log.ErrorTree[typeClash, v]; ENDCASE => IF subType # typeANY THEN Log.ErrorTree[typeClash, v]; RETURN}; dataPtr.textIndex _ tb[node].info; tb[node].son[1] _ UpdateList[tb[node].son[1], CatchLabel]; IF mixed THEN type _ typeANY; tb[node].son[2] _ CatchBody[ tb[node].son[2], type, safe OR (error AND enclosingSafe)]; IF tb[node].son[1] = Tree.Link[symbol[index: dataPtr.idUNWIND]] THEN { unwindCaught _ TRUE; IF current.entry AND ~current.unwindEnabled AND current.catchDepth = 0 THEN { PushTree[tb[node].son[2]]; PushTree[CopyLock[]]; PushNode[unlock, 1]; SetInfo[dataPtr.textIndex]; tb[node].son[2] _ MakeList[2]}}; tb[node].info _ IF type # typeANY THEN type ELSE SENull; dataPtr.textIndex _ saveIndex; RETURN}; CatchBody: PROC [body: Tree.Link, type: CSEIndex, safe: BOOL] RETURNS [val: Tree.Link] = { saveRecord: RecordSEIndex = current.resumeRecord; saveFlag: BOOL = current.resumeFlag; current.catchDepth _ current.catchDepth + 1; WITH t: seb[type] SELECT FROM transfer => { current.resumeFlag _ t.mode = signal; PushArgCtx[t.typeIn]; BumpArgRefs[ArgRecord[t.typeIn], TRUE]; PushArgCtx[current.resumeRecord _ ArgRecord[t.typeOut]]; ClearRefStack[]}; ENDCASE => { current.resumeFlag _ FALSE; current.resumeRecord _ RecordSENull}; current.reachable _ TRUE; pathNP _ entryNP; SELECT OpName[body] FROM block, checked => SetSafety[SafetyAttr[GetNode[body]]]; ENDCASE; IF safe AND P3S.safety = none THEN Log.Error[unsafeBlock]; val _ UpdateList[body, Stmt ! InsertCatchLabel => {IF catchSeen THEN RESUME}]; exitNP _ BoundNP[exitNP][pathNP]; WITH t: seb[type] SELECT FROM transfer => {PopArgCtx[t.typeOut]; PopArgCtx[t.typeIn]}; ENDCASE; current.catchDepth _ current.catchDepth - 1; current.resumeRecord _ saveRecord; current.resumeFlag _ saveFlag; SetSafety[saveSafety]; RETURN}; setLabel, continued: BOOL; node: Tree.Index = GetNode[t]; SealRefStack[]; setLabel _ continued _ unwindCaught _ FALSE; entryNP _ exitNP _ none; BEGIN ENABLE InsertCatchLabel => { IF ~catchSeen THEN { setLabel _ TRUE; IF exit THEN continued _ TRUE; SIGNAL InsertCatchLabel[catchSeen:TRUE, exit:exit]; RESUME}}; ScanList[tb[node].son[1], CatchItem]; IF tb[node].nSons > 1 THEN tb[node].son[2] _ CatchBody[tb[node].son[2], typeANY, enclosingSafe]; END; IF setLabel THEN {P3S.markCatch _ TRUE; P3S.continued _ continued}; UnsealRefStack[]; current.reachable _ saveReachable; phraseNP _ exitNP; pathNP _ savePathNP; RETURN}; PushArgCtx: PROC [sei: CSEIndex] = { ctx: CTXIndex = ArgCtx[sei]; IF ctx # CTXNull THEN { ctxb[ctx].level _ current.level + current.catchDepth; PushCtx[ctx]}}; PopArgCtx: PROC [sei: CSEIndex] = { ctx: CTXIndex = ArgCtx[sei]; IF ctx # CTXNull THEN {PopCtx[]; ctxb[ctx].level _ lZ}}; Resume: PROC [node: Tree.Index] = { OPEN tb[node]; rSei: RecordSEIndex = current.resumeRecord; IF ~current.resumeFlag THEN Log.Error[misplacedResume]; IF rSei # SENull AND son[1] = Tree.Null THEN { n: CARDINAL _ 0; BumpArgRefs[rSei, FALSE]; FOR sei: ISEIndex _ FirstCtxSe[seb[rSei].fieldCtx], NextSe[sei] UNTIL sei = SENull DO n _ n+1; IF n=1 AND seb[sei].hash = HTNull THEN Log.Error[illDefinedReturn]; PushSe[sei]; ENDLOOP; son[1] _ MakeList[n]} ELSE { son[1] _ IF attr1 AND rSei # SENull THEN Rhs[son[1], rSei] ELSE MatchFields[rSei, son[1]]; RPop[]; pathNP _ SequenceNP[pathNP][phraseNP]}; current.reachable _ FALSE}; CheckHash: PROC [hti: HTIndex, s: LONG STRING] RETURNS [BOOL] = { desc: ConvertUnsafe.SubString; desc _ [base: s, offset: 0, length: s.length]; RETURN [FindString[desc] = hti]}; TextRep: PUBLIC PROC [rType: SEIndex] RETURNS [form: TextForm _ text] = { type: CSEIndex = UnderType[rType]; rope: STRING = "Rope"L; ropeRep: STRING = "RopeRep"L; textRep: STRING = "TextRep"L; WITH se: seb[rType] SELECT FROM id => IF CheckHash[se.hash, ropeRep] THEN form _ rope ELSE IF CheckHash[se.hash, textRep] THEN form _ ropeText; ENDCASE; WITH t: seb[type] SELECT FROM record => WITH c: ctxb[t.fieldCtx] SELECT FROM included => IF ~CheckHash[mdb[c.module].moduleId, rope] THEN form _ text; ENDCASE => form _ text; ENDCASE => form _ text; RETURN}; }. „file Pass3M.mesa last modified by Satterthwaite, May 10, 1983 9:21 am last modified by Donahue, 9-Dec-81 14:45:35 Last Edited by: Maxwell, July 28, 1983 11:46 am called by allocator whenever table area is repacked statements check for simple addressability dynamic storage allocation list allocation control transfers monitors signals catch phrases Rope identification (temporary) Ê9˜Jšœ™Jšœ4™4Jšœ,™,J™/J˜šÏk ˜ šœœœ˜J˜MJ˜:—Jšœœœ˜"šœ œœ˜J˜DJ˜&—Jšœœœ ˜&Jšœœœ˜-Jšœœœ ˜šœœœ˜J˜(J˜6J˜;J˜MJ˜8J˜SJ˜9—Jšœœœ7˜Fšœ œœ˜J˜PJ˜(J˜AJ˜=—šœ œœ˜J˜EJ˜F—JšœœœE˜Ušœ œœ˜J˜J˜;—Jšœœœ˜+J˜—šœ˜š˜J˜3J˜ —Jšœ˜Jšœ%˜)J˜Jš œœœœœ˜?J˜JšœÏc!˜0Jšœž%˜8Jšœž"˜6Jšœž!˜4Jšœž˜1J˜šœ œ˜%Jšœ3™3J˜J˜?J˜J˜—Jšœ œœ!˜4J˜Jšœ ™ ˜šÏnœœœœ˜EJšœž˜,Jšœ˜˜˜%šœ œ˜"J˜J˜J˜Jšœ˜—šœ ˜Jšœœ˜Jšœ˜"—J˜6J˜&Jšœœœ˜7J˜—˜ J˜Jšœœ˜:J˜J˜.Jšœœ˜8šœ˜J˜+Jšœœ˜—Jšœ8œ˜>Jšœœ5˜JJšœœ˜8Jšœœ˜J˜—J˜J˜˜ Jšœœ˜:Jšœœ˜J˜—˜Jšœœ˜FJšœœ˜J˜—J˜HJ˜˜ šœœ˜8Jšœœ˜?—Jšœœ˜2J˜—˜Jšœ ˜J˜Jšœœ ˜9J˜Jšœœ˜@J˜@Jšœœ#˜GJ˜—˜ Jšœ ˜J˜Jšœœ˜J˜CJ˜8J˜šœœ˜ ˜Jšœ œ˜1J˜Jšœ#œœœ˜5J˜šœœ˜Jš œœœœœ˜.Jšœœœ˜—šœœ ˜)J˜0—š˜J˜*——Jšœ%˜,—šœ œ˜J˜J˜A—J˜šœœ˜Jšœœ˜JšœBœ˜IJšœ5˜J˜&Jšœ™š˜šœœ˜Jš œ œœœœœœ˜;˜ Jšœœœœ˜B—Jšœœœ˜—Jšœ˜—Jšœœ1˜Mš˜J˜0J˜——˜ Jšœ ˜Jšœ œ˜*Jšœ"œœ˜FJšœœ˜(Jšœ,œ˜2J˜%J˜—Jšœ˜$J˜—Jšœ˜J˜J˜——Jšœ™˜šŸœœ&œ˜FJšœ ˜J˜J˜J˜ J˜Jšœœ˜J˜:J˜,Jšœ œœ˜;J˜J˜HJ˜=Jšœœ#˜@Jšœ œœ˜+Jšœœ˜8Jšœ˜˜š Ÿ œœœœœ˜9šœœ ˜Jšœœ˜J˜0Jšœœ˜J˜——Jšœ œ˜J˜0šœœ˜J˜0J˜9Jšœ˜ ——J˜M˜J˜;J˜—šœ œ˜&Jšœ+œ˜1—šœœ˜1J˜,—šœ œ˜J˜J˜A—J˜Jšœœœœ˜AJšœ˜!J˜—šŸœœœœ˜MJ˜Jšœ œ˜Jšœœ˜Jšœœ+˜@šœ˜J˜3š˜J˜šœœ˜Jšœ-œœ ˜<˜Jšœœœœ ˜3J˜JJ˜=—˜ Jšœœœ˜KJšœœœ ˜—Jšœœœ ˜—š˜Jšœ œ˜J˜'—Jšœ˜ ——Jšœ˜J˜——Jšœ™˜šŸœœ&œ˜GJ˜4J˜8J˜)J˜8Jšœ7œ˜>šœœ˜J˜I—Jšœ˜J˜Jšœ˜!J˜—šŸœœ&œ˜KJ˜4Jšœœ˜*Jšœœ˜J˜J˜˜Jšœ œ œœ˜:J˜)J˜+Jšœ7œ˜>J˜Jšœ˜J˜—J˜.Jšœœ1˜>šœ˜J˜5J˜@—J˜Jšœ˜J˜—šŸœœ"œ˜MJ˜'šœœ˜ ˜J˜'šœ œœ˜AJ˜)—šœ˜Jšœ œ˜,J˜——šœ˜ Jšœœ*˜CJšœ0˜4——Jšœ˜J˜J˜——Jšœ™˜šŸœœœ&œ˜Wšœ˜J˜J˜&J˜%J˜J˜!J˜J˜!J˜)Jšœ6˜=—Jšœ˜J˜J˜—šŸœœœœ˜HJ˜šœœ˜J˜8šœœœ˜:Jšœ ˜Jšœ ˜$——Jšœ*˜.Jšœ˜J˜—šŸœœ œ˜VJšœœ*œ˜?šœœ œ˜.˜Jšœ œ˜Jšœ œ œ˜˜Jšœ œ œ˜ Jšœ œœœ˜:Jšœ œ œ œ˜1—J˜Jšœœœœ˜LJ˜J˜——Jšœ˜J˜J˜—šŸœœœ˜9J˜J˜šœœ˜˜ J˜0šœœ œ˜ ˜ šœ˜Jšœ˜ š˜šœ˜˜ šœ˜Jšœœœœ ˜=Jšœ ˜ ——˜Jšœ œœ ˜F—Jšœ ˜————Jšœ ˜——Jšœ˜—Jšœ˜J˜—šŸ œœœœ˜PJšœœ˜J˜1šœ˜šœœ˜˜ Jšœœœ˜>šœ œœ˜$Jšœ#œ˜(Jšœ#œ˜(Jšœœ˜,——Jšœ!œ˜-—Jšœ˜—Jšœ ˜J˜J˜—šŸœœ&œ˜NJ˜J˜(J˜-˜Jšœœ ˜J˜J˜ J˜JšŸ œœ6˜GJ˜Jšœœ˜J˜J˜Gšœ œ˜˜ šœ˜šœ˜J˜˜ šœœ˜#Jšœ-˜1Jšœ˜ —Jšœœ˜—Jšœ˜——Jšœ˜—˜J˜)šœ œ˜˜ šœœ˜J˜-˜%J˜Jšœœ-˜C—Jšœ˜——Jšœœœ˜5——Jšœœœœ˜E—šœœ˜J˜L—Jšœ œ˜+Jšœ œœ˜;J˜Jšœ˜—Jšœ˜J˜J˜—šŸœœœ˜6J˜JšœEœ˜Kšœ˜Jšœœ˜Jšœ1˜8—J˜-Jšœ˜J˜J˜—šŸœœœ˜=J˜J˜J˜(˜Jšœœ ˜J˜,J˜8J˜šœ œ˜Jšœœž˜%˜ Jšœœœ"˜V—Jšœœœ"˜C—šœœ˜J˜L—Jšœ œ˜+Jšœ˜—Jšœœ˜Jšœ/œ˜7J˜J˜—šŸœœ&œ˜GJ˜J˜J˜ J˜1J˜-Jšœ%œ˜Ešœ˜˜J˜"J˜šœœ˜J˜3—šœœ˜/J˜—J˜šœœ˜'˜ Jšœ+œ˜1šœœ œ˜.˜J˜#J˜J˜——Jšœœ˜˜˜J˜#J˜(šœœ˜ Jšœœœ+˜@J˜'Jšœ ˜—Jšœ˜J˜—J˜,J˜@——Jšœœ˜—J˜—J˜Jšœ@˜G—J˜,Jšœ˜J˜—šŸœœœ˜5J˜JšœEœ˜Kšœ˜Jšœœ˜Jšœ œ˜Jšœ1˜8—J˜-Jšœ˜J˜—šŸœœœ˜:J˜J˜Jšœœ ˜9JšœEœ˜Kšœ˜Jšœœ˜ Jšœ œ˜Jšœ1˜8—J˜-Jšœ'œ+˜XJ˜"J˜J˜JJ˜%Jšœ˜J˜J˜——Jšœ™˜šŸœœœœ˜@J˜J˜J˜Jšœ œ˜Jšœ œ˜J˜šŸ œœ˜&J˜HJ˜J˜—J˜-J˜&š˜Jš œœœ œœœ ˜WJ˜<šœ œ˜˜ šœ œ˜J˜&J˜6Jšœœ-˜7J˜Jšœ œ œœ ˜1J˜?Jšœœ ˜—Jšœœ ˜—˜Jšœœœœ ˜3J˜ Jšœ œ˜&J˜—Jšœœœ ˜—š˜Jšœ œ˜J˜)—Jšœ˜—Jšœœ˜:Jšœ˜J˜—šŸœœœœ˜BJ˜8Jšœœ˜ Jšœœ˜7šœ˜J˜Jšœœ ˜2šœ!˜%J˜J˜#—Jšœœ˜!—Jšœ˜J˜J˜—JšŸ œœ*œ˜U˜šŸ œœœ˜8Jšœœœœ ˜@J˜—J˜J˜Jšœ˜J˜—šŸœœœœ˜2J˜šœœ˜J˜5˜*J˜A—šœ˜ J˜2šœœ˜Jšœœ>˜Ušœ˜J˜4Jšœ5˜9J˜!——J˜@——Jšœ˜J˜J˜——Jšœ™˜šŸœœœœ˜CJ˜J˜'JšœEœ˜Kšœ˜J˜.˜šœ œ˜J˜@Jšœœ˜—J˜—Jšœ œ˜Jšœ1˜8—J˜-Jšœ˜J˜—šŸœœœ˜=Jšœœœ˜&J˜"Jšœ˜J˜J˜——Jšœ ™ J˜˜š Ÿ œœœœœ˜HJšœœ˜(J˜J˜ Jšœœ˜-J˜J˜˜J˜J˜Jšœœœ˜!Jšœ œ˜(J˜˜J˜J˜@J˜(šœœ˜ ˜ šœœœ˜+Jšœœ˜%šœœ˜Jšœ;˜?Jšœœ˜ —Jšœœœ˜Jšœœ œ˜$—Jšœ˜!—Jšœœœ˜A—Jšœ˜J˜—J˜"J˜:Jšœœ˜˜Jšœœœ˜:—šœ>œ˜FJšœœ˜šœœœœ˜MJ˜1J˜1J˜ ——Jšœœœœ˜8Jšœ œ˜(J˜—šŸ œœ)œ˜=Jšœ˜J˜2Jšœ œ˜$J˜,šœœ˜˜ J˜%J˜Jšœ!œ˜'J˜8J˜—šœ˜ Jšœœ'˜A——Jšœœ˜,šœ˜J˜8Jšœ˜—Jšœœœ˜:Jšœ3œ œœ˜NJ˜!šœœ˜J˜8Jšœ˜—J˜,J˜BJšœœ˜ J˜—Jšœœ˜J˜J˜šœ&œ˜FJš˜šœ˜šœ œ˜Jš œ œœœ œ˜0Jšœœœ˜=——J˜%šœ˜J˜E—Jšœ˜—Jšœ œœ˜CJ˜5Jšœ*œ˜2J˜—šŸ œœ˜$J˜šœœ˜J˜EJ˜——šŸ œœ˜#J˜Jšœœ#˜8J˜J˜—šŸœœ˜#Jšœ ˜J˜+Jšœœ˜7šœœœ˜.Jšœœ˜Jšœœ˜šœ=œ˜UJ˜ Jšœœœ˜CJ˜ Jšœ˜—J˜—šœ˜šœ œœ˜#Jšœ˜Jšœ˜—J˜J˜'—Jšœœ˜J˜J˜——Jšœ™˜š Ÿ œœœœœœ˜AJ˜J˜.Jšœ˜!J˜—šŸœœœœ˜IJ˜"Jšœœ ˜Jšœ œ˜Jšœ œ˜šœœ˜˜Jšœœ ˜/Jšœœœ˜9—Jšœ˜—šœœ˜˜ šœœ˜$Jšœ œ*œ ˜IJšœ˜——Jšœ˜—Jšœ˜J˜—J˜J˜———…—gœƒY