DIRECTORY AMBridge USING [GetWorld, IsRemote, nilRemoteFrameHandle, nilRemoteGlobalFrameHandle, RemoteFHFromTV, RemoteFrameHandle, RemoteGFHFromTV, RemoteGlobalFrameHandle, RemotePD, RemoteSED, TVForProc, TVForRemoteFrame, TVForRemoteGFHReferent, TVForRemoteProc, TVForRemoteSignal, TVForSignal, TVToCardinal, TVToRemoteProc,TVToRemoteSignal, WordSequence, WordSequenceRecord], AMProcessBasic USING [ReturnLink], AMTypes USING [Domain, Error, Index, IndexToTV, Range, Size, TV, TVStatus, TVType, UnderClass, UnderType], BrandXSymbolDefs USING [SymbolTableBase, rootBodyIndex, BodyIndex, nullBodyIndex, outerContextLevel], BrandYSymbolDefs USING [SymbolTableBase, rootBodyIndex, BodyIndex, nullBodyIndex, outerContextLevel], LoadState USING [GlobalFrameToType, local, Acquire, Release], PrincOps USING [BytePC, ControlLink, CSegPrefix, EPRange, Frame, FrameHandle, GlobalFrame, GlobalFrameHandle, localbase, MaxNGfi, NullLink, ProcDesc, SignalDesc, StateVector, UnboundLink, SD, sSignal], PrincOpsUtils USING [GlobalFrame, Codebase], RemotePrincOpsUtils USING [RemoteGlobalFrame], Rope USING [ROPE], RTSymbolDefs USING [BlockContextLevel, BodyIndex, CallableBodyIndex, nullBodyIndex, SymbolConstructorIndex, SymbolIdIndex, SymbolIndex, SymbolTableBase], RTSymbolOps USING [AcquireType, BodyLevel, BodyType, CallableBodyEntryIndex, CallableBTI, ISEConstant, ISEImmutable, ISEType, IsRootBTI, IsTypeSEI, NullBTI, NullSEI, ParentBody, RootBodyType, SEUnderType], RTSymbols USING [AcquireSTBFromGFH, OuterFromGFH, ReleaseSTB], RTTypesPrivate USING [BuildRecordFieldDescriptor, FieldDescriptor, GetIdConstantValue, GFHToName, RecordComponentISEI, TypedVariableRec, UnwindIndirectProcDesc], RTTypesRemotePrivate USING [AcquireBTIFromRemoteFH, AcquireSTBFromRemoteGFH, GetRemoteEp, GetRemoteFrameHeader, GetRemoteGFHeader, IsRemoteCatchFrame, OuterFromRemoteGFH, RemoteGFHToName, RemoteSignalValues], RuntimeError USING [UNCAUGHT], SafeStorage USING [Type, nullType, fhType, gfhType], WorldVM USING [CurrentIncarnation, Long, ShortAddress, World, LocalWorld]; RTTypedFramesImpl: PROGRAM IMPORTS AMBridge, AMProcessBasic, AMTypes, LoadState, PrincOpsUtils, RemotePrincOpsUtils, RTSymbolOps, RTSymbols, RTTypesPrivate, RTTypesRemotePrivate, RuntimeError, WorldVM EXPORTS AMTypes, AMBridge, RTTypesPrivate = BEGIN OPEN AMBridge, AMTypes, bx: BrandXSymbolDefs, by: BrandYSymbolDefs, RemotePrincOpsUtils, Rope, RTSymbolDefs, RTSymbolOps, RTSymbols, SafeStorage, RTTypesPrivate, RTTypesRemotePrivate, RuntimeError, WorldVM; EVRange: TYPE = [0..4*PrincOps.EPRange); sigGF: PrincOps.GlobalFrameHandle = LOOPHOLE[ PrincOpsUtils.GlobalFrame[LOOPHOLE[PrincOps.SD[PrincOps.sSignal], PrincOps.ProcDesc]]]; TVToSignal: PUBLIC PROC [tv: TV] RETURNS [ERROR ANY RETURNS ANY] = { SELECT UnderClass[TVType[tv]] FROM signal, error => NULL; nil => RETURN[LOOPHOLE[PrincOps.UnboundLink, ERROR ANY RETURNS ANY]]; ENDCASE => RaiseClassError[tv]; RETURN[LOOPHOLE[TVToCardinal[tv], ERROR ANY RETURNS ANY]]; }; TVForFrame: PUBLIC PROC [ fh: PrincOps.FrameHandle, evalStack: POINTER TO PrincOps.StateVector _ NIL, return: BOOL _ FALSE, contextPC: BOOL _ FALSE] RETURNS [ans: TV _ NIL] = { bti: BodyIndex; isCatchFrame: BOOL _ FALSE; IF fh = NIL THEN RETURN[NIL]; [isCatchFrame, bti] _ AcquireBTIFromFH[fh, contextPC ! Error => IF reason = noSymbols THEN {bti _ nullBodyIndex; CONTINUE}]; RETURN[NEW[TypedVariableRec _ [referentType: [fhType], head: [fh[fh: fh, evalStack: evalStack, bti: bti, isCatchFrame: isCatchFrame, return: return, contextPC: contextPC]], status: mutable, field: entire[] ]]]; }; FHFromTV: PUBLIC PROC [tv: TV] RETURNS [PrincOps.FrameHandle _ NIL] = { IF tv = NIL THEN RETURN[NIL]; WITH tv SELECT FROM tr: REF TypedVariableRec => WITH tfh: tr.head SELECT FROM fh => RETURN[tfh.fh]; ENDCASE => GO TO oops; ENDCASE => GO TO oops; EXITS oops => RaiseClassError[tv] }; TVForGFHReferent: PUBLIC PROC [gfh: PrincOps.GlobalFrameHandle] RETURNS [TV _ NIL] = { IF gfh # NIL THEN RETURN[NEW[TypedVariableRec _ [referentType: [gfhType], head: [gfh[gfh: gfh]], status: mutable, field: entire[]]]]; }; GFHFromTV: PUBLIC PROC [tv: TV] RETURNS [PrincOps.GlobalFrameHandle _ NIL] = { IF tv = NIL THEN RETURN[NIL]; WITH tv SELECT FROM tr: REF TypedVariableRec => WITH tgfh: tr.head SELECT FROM gfh => RETURN[tgfh.gfh]; ENDCASE; ENDCASE; RaiseClassError[tv] }; GlobalParent: PUBLIC SAFE PROC [tv: TV--transfer or local frame--] RETURNS [TV--globalFrame--] = TRUSTED { IF IsRemote[tv] THEN { type: Type = TVType[tv]; gfh: RemoteGlobalFrameHandle _ nilRemoteGlobalFrameHandle; SELECT UnderClass[type] FROM localFrame => { fh: RemoteFrameHandle = RemoteFHFromTV[tv]; IF fh.fh = 0 THEN RETURN[NIL]; gfh _ [world: fh.world, worldIncarnation: CurrentIncarnation[fh.world], gfh: LOOPHOLE[GetRemoteFrameHeader[fh].accesslink, WorldVM.ShortAddress]]; }; program, procedure => { pd: RemotePD = TVToRemoteProc[tv]; IF pd.pd = LOOPHOLE[PrincOps.NullLink, WORD] THEN RETURN[NIL]; gfh _ [world: pd.world, worldIncarnation: CurrentIncarnation[pd.world], gfh: LOOPHOLE[RemoteGlobalFrame[pd.world, pd.pd], WorldVM.ShortAddress]]; }; signal, error => { sed: RemoteSED = TVToRemoteSignal[tv]; IF sed.sed = LOOPHOLE[PrincOps.NullLink, WORD] OR LOOPHOLE[sed.sed, CARDINAL] = 177777B OR LOOPHOLE[sed.sed, CARDINAL] = LOOPHOLE[UNWIND, CARDINAL] OR LOOPHOLE[sed.sed, CARDINAL] = LOOPHOLE[ABORTED, CARDINAL] THEN RETURN[NIL]; gfh _ [ world: sed.world, worldIncarnation: CurrentIncarnation[sed.world], gfh: LOOPHOLE[RemoteGlobalFrame[sed.world, sed.sed], WorldVM.ShortAddress]]; }; nil => RETURN[NIL]; ENDCASE => ERROR Error[reason: typeFault, type: type]; RETURN[TVForRemoteGFHReferent[gfh]]; } ELSE { type: Type = TVType[tv]; gfh: PrincOps.GlobalFrameHandle; SELECT UnderClass[type] FROM localFrame => { fh: PrincOps.FrameHandle = FHFromTV[tv]; IF fh = NIL THEN RETURN[NIL]; gfh _ fh.accesslink; }; signal, error => { sed: PrincOps.ProcDesc = LOOPHOLE[TVToSignal[tv], PrincOps.ProcDesc]; IF sed = PrincOps.NullLink OR LOOPHOLE[sed, CARDINAL] = 177777B OR LOOPHOLE[sed, CARDINAL] = LOOPHOLE[UNWIND, CARDINAL] OR LOOPHOLE[sed, CARDINAL] = LOOPHOLE[ABORTED, CARDINAL] THEN RETURN[NIL]; gfh _ LOOPHOLE[PrincOpsUtils.GlobalFrame[sed], PrincOps.GlobalFrameHandle]; }; program, procedure => { pd: PrincOps.ProcDesc = UnwindIndirectProcDesc[LOOPHOLE[TVToCardinal[tv], PrincOps.ControlLink]]; IF pd = PrincOps.NullLink THEN RETURN[NIL]; gfh _ LOOPHOLE[PrincOpsUtils.GlobalFrame[pd], PrincOps.GlobalFrameHandle]; }; nil => RETURN[NIL]; ENDCASE => ERROR Error[reason: typeFault, type: type]; RETURN[TVForGFHReferent[gfh]]; }; }; ContextPC: PUBLIC SAFE PROC [tv: TV--localFrame--] RETURNS [ans: PrincOps.BytePC] = TRUSTED { WITH th: NARROW[tv, REF TypedVariableRec].head SELECT FROM remoteFH => ans _ [GetRemoteFrameHeader[RemoteFHFromTV[tv]].pc - (IF th.contextPC THEN 0 ELSE 1)]; fh => ans _ [th.fh.pc - (IF th.contextPC THEN 0 ELSE 1)]; ENDCASE => RaiseClassError[tv]; }; IsStarted: PUBLIC SAFE PROC [tv: TV--globalFrame--] RETURNS [BOOL _ FALSE] = TRUSTED { rtr: REF TypedVariableRec _ NARROW[tv]; IF IsRemote[tv] THEN { rgfh: REF PrincOps.GlobalFrame = GetRemoteGFHeader[RemoteGFHFromTV[tv]]; RETURN[(NOT rgfh.code.out) OR rgfh.started]; } ELSE WITH th: rtr.head SELECT FROM gfh => RETURN[(NOT th.gfh.code.out) OR th.gfh.started]; ENDCASE => RaiseClassError[tv]; }; IsCopied: PUBLIC SAFE PROC [tv: TV--globalFrame--] RETURNS [BOOL _ FALSE] = TRUSTED { rtr: REF TypedVariableRec _ NARROW[tv]; IF IsRemote[tv] THEN { rgfh: REF PrincOps.GlobalFrame = GetRemoteGFHeader[RemoteGFHFromTV[tv]]; RETURN[rgfh.copied]; } ELSE WITH th: rtr.head SELECT FROM gfh => RETURN[th.gfh.copied]; ENDCASE => RaiseClassError[tv]; }; Procedure: PUBLIC SAFE PROC [tv: TV--localFrame--] RETURNS [TV--procedure--] = TRUSTED { IF IsRemote[tv] THEN { stb: SymbolTableBase; rtr: REF TypedVariableRec; bti: BodyIndex; fh: RemoteFrameHandle _ nilRemoteFrameHandle; IF tv = NIL THEN RETURN[NIL]; rtr _ NARROW[tv]; WITH th: rtr.head SELECT FROM remoteFH => IF th.isCatchFrame THEN bti _ nullBodyIndex ELSE { bti _ th.bti; IF NullBTI[bti] THEN { name: ROPE; fh _ RemoteFHFromTV[tv]; bti _ th.bti _ AcquireBTIFromRemoteFH[fh, th.contextPC]; IF NOT NullBTI[th.bti] THEN { [th.isCatchFrame, th.bti] _ IsRemoteCatchFrame[fh, bti]; bti _ th.bti; IF th.isCatchFrame THEN bti _ nullBodyIndex; } ELSE { name _ RemoteGFHToName [[world: fh.world, worldIncarnation: CurrentIncarnation[fh.world], gfh: LOOPHOLE[GetRemoteFrameHeader[fh].accesslink, WorldVM.ShortAddress]]]; ERROR AMTypes.Error[reason: noSymbols, msg: name]; }; }; }; ENDCASE => bti _ nullBodyIndex; IF NullBTI[bti] THEN RaiseClassError[tv]; fh _ RemoteFHFromTV[tv]; IF fh.fh = 0 THEN RETURN[NIL]; stb _ AcquireSTBFromRemoteGFH [[world: fh.world, worldIncarnation: CurrentIncarnation[fh.world], gfh: LOOPHOLE[GetRemoteFrameHeader[fh].accesslink, WorldVM.ShortAddress]]]; FOR bti _ bti, ParentBody[stb, bti] UNTIL NullBTI[bti] DO IF CallableBTI[stb, bti] THEN { sppd: PrincOps.ProcDesc _ LOOPHOLE[PrincOps.UnboundLink, PrincOps.ProcDesc]; entryIndex: [0..PrincOps.EPRange*PrincOps.MaxNGfi) _ CallableBodyEntryIndex[stb, LOOPHOLE[bti, CallableBodyIndex]]; IF entryIndex = 0 THEN RaiseClassError[tv]; sppd.gfi _ GetRemoteGFHeader [[world: fh.world, worldIncarnation: CurrentIncarnation[fh.world], gfh: LOOPHOLE[GetRemoteFrameHeader[fh].accesslink, WorldVM.ShortAddress] ]].gfi + entryIndex/PrincOps.EPRange; sppd.ep _ entryIndex MOD PrincOps.EPRange; ReleaseSTB[stb]; RETURN[TVForRemoteProc[[fh.world, CurrentIncarnation[fh.world], LOOPHOLE[sppd]]]]; }; ENDLOOP; ReleaseSTB[stb]; RETURN[NIL]; } ELSE { stb: SymbolTableBase; rtr: REF TypedVariableRec; bti: BodyIndex; fh: PrincOps.FrameHandle; IF tv = NIL THEN RETURN[NIL]; rtr _ NARROW[tv]; WITH th: rtr.head SELECT FROM fh => IF th.isCatchFrame THEN RaiseClassError[tv] ELSE { bti _ th.bti; IF NullBTI[bti] -- no symbols for this localFrame TV THEN { fh _ FHFromTV[tv]; bti _ th.bti _ AcquireBTIFromFH[fh, th.contextPC ! UNCAUGHT => CONTINUE].bti; IF NOT NullBTI[th.bti] THEN { [th.isCatchFrame, th.bti] _ IsCatchFrame[fh, bti]; bti _ th.bti; IF th.isCatchFrame THEN RaiseClassError[tv]; } ELSE ERROR AMTypes.Error[reason: noSymbols, msg: GFHToName[th.fh.accesslink]]; }; }; ENDCASE => RaiseClassError[tv]; fh _ FHFromTV[tv]; IF fh = NIL THEN RETURN[NIL]; stb _ AcquireSTBFromGFH[fh.accesslink]; FOR bti _ bti, ParentBody[stb, bti] UNTIL NullBTI[bti] DO IF CallableBTI[stb, bti] THEN { sppd: PrincOps.ProcDesc _ LOOPHOLE[PrincOps.UnboundLink, PrincOps.ProcDesc]; entryIndex: [0..PrincOps.EPRange*PrincOps.MaxNGfi) _ CallableBodyEntryIndex[stb, LOOPHOLE[bti, CallableBodyIndex]]; sppd.gfi _ fh.accesslink.gfi + entryIndex/PrincOps.EPRange; sppd.ep _ entryIndex MOD PrincOps.EPRange; ReleaseSTB[stb]; RETURN[TVForProc[LOOPHOLE[sppd, PROC ANY RETURNS ANY]]]; }; ENDLOOP; ReleaseSTB[stb]; ERROR; }; }; Signal: PUBLIC SAFE PROC [tv: TV--localFrame--] RETURNS [ans: TV--signal descriptor--] = TRUSTED { IF IsRemote[tv] THEN { world: World; sed: PrincOps.SignalDesc; [world: world, signal: sed] _ RemoteSignalValues[tv]; ans _ TVForRemoteSignal[[world: world, worldIncarnation: CurrentIncarnation[world], sed: LOOPHOLE[sed]]] } ELSE ans _ TVForSignal[LOOPHOLE[RemoteSignalValues[tv].signal, ERROR ANY RETURNS ANY]]}; IsCatch: PUBLIC SAFE PROC [tv: TV] RETURNS [BOOL] = TRUSTED { type: Type = TVType[tv]; IF type = fhType THEN WITH tv SELECT FROM rtr: REF TypedVariableRec => { bti: BodyIndex _ nullBodyIndex; isCatch: BOOL _ FALSE; WITH th: rtr.head SELECT FROM remoteFH => {bti _ th.bti; isCatch _ th.isCatchFrame}; fh => {bti _ th.bti; isCatch _ th.isCatchFrame}; ENDCASE => RETURN [FALSE]; IF bti # nullBodyIndex THEN RETURN [isCatch]; [] _ Procedure[tv ! AMTypes.Error => IF reason = typeFault THEN {isCatch _ FALSE; CONTINUE}]; RETURN [isCatch]; }; ENDCASE; RETURN [FALSE]; }; Argument: PUBLIC SAFE PROC [tv: TV--local or catch Frame--, index: Index] RETURNS [TV] = TRUSTED { RETURN[ArgOrResult[tv, index, Domain]]; }; Result: PUBLIC SAFE PROC [tv: TV--local or catch Frame--, index: Index] RETURNS [TV] = TRUSTED { RETURN[ArgOrResult[tv, index, Range]]; }; ArgOrResult: PROC [tv: TV--local or catch Frame--, index: Index, domainOrRange: PROC [Type] RETURNS [Type] ] RETURNS [TV] = { type: Type; catch: BOOL; message: WORD; world: World; argsTV: REF TypedVariableRec; tvr: REF TypedVariableRec _ NARROW[tv]; offset: INTEGER _ 0; GetSignalOrProcType: PROC [tv: TV] RETURNS [type: Type _ nullType, catch: BOOL _ FALSE] = { rtr: REF TypedVariableRec _ NARROW[tv]; WITH th: rtr.head SELECT FROM fh => { catch _ th.isCatchFrame; type _ TVType[IF catch THEN Signal[tv] ELSE Procedure[tv]]; }; remoteFH => { catch _ th.isCatchFrame; type _ TVType[IF catch THEN Signal[tv] ELSE Procedure[tv]]; }; ENDCASE => RaiseClassError[tv]; }; IF tv = NIL THEN ERROR Error[reason: typeFault, type: nullType]; [type, catch] _ GetSignalOrProcType[tv]; IF type = nullType THEN ERROR Error[reason: badIndex]; type _ domainOrRange[type]; IF type = nullType THEN ERROR Error[reason: badIndex]; WITH tvh: tvr.head SELECT FROM fh, remoteFH => NULL; ENDCASE => ERROR Error[reason: typeFault, type: type]; IF ~catch OR domainOrRange = Range THEN { BuildEmbeddedTV: PROC [stb: SymbolTableBase, isei: SymbolIdIndex] = { sei: SymbolIndex = ISEType[stb, isei]; csei: SymbolConstructorIndex _ SEUnderType[stb, sei]; bitsForType: LONG CARDINAL _ (WITH stb SELECT FROM t: SymbolTableBase.x => t.e.BitsForType[NARROW[csei, SymbolConstructorIndex.x].e], t: SymbolTableBase.y => t.e.BitsForType[NARROW[csei, SymbolConstructorIndex.x].e], ENDCASE => ERROR); -- bits for the value in the field fieldBits: CARDINAL _ (WITH stb SELECT FROM t: SymbolTableBase.x => t.e.seb[NARROW[isei, SymbolIdIndex.x].e].idInfo, t: SymbolTableBase.y => t.e.seb[NARROW[isei, SymbolIdIndex.x].e].idInfo, ENDCASE => ERROR); -- bits for the field fieldBitOffset: CARDINAL _ (WITH stb SELECT FROM t: SymbolTableBase.x => t.e.seb[NARROW[isei, SymbolIdIndex.x].e].idValue, t: SymbolTableBase.y => t.e.seb[NARROW[isei, SymbolIdIndex.x].e].idValue, ENDCASE => ERROR); cType: Type _ AcquireType[stb, sei]; IF ISEConstant[stb, isei] THEN { IF IsRemote[tv] AND IsTypeSEI[ISEType[stb, isei]] THEN argsTV _ NEW[TypedVariableRec _ [referentType: [cType], head: [constant[]], -- type code is valid in local world status: const, field: constant[value: GetIdConstantValue[tv, stb, isei]]]] ELSE -- either a constant component of a local tv or not a type constant argsTV _ NEW[TypedVariableRec _ [referentType: [cType], head: (WITH tv SELECT FROM tr: REF TypedVariableRec => tr.head, ENDCASE => ERROR), status: const, field: constant[value: GetIdConstantValue[tv, stb, isei]]]]; } ELSE argsTV _ NEW[TypedVariableRec _ [referentType: [cType], head: (WITH tv SELECT FROM tr:REF TypedVariableRec => tr.head, ENDCASE => ERROR), status: (IF ISEImmutable[stb, isei] THEN readOnly ELSE TVStatus[tv]), field: embedded[ fd: BuildRecordFieldDescriptor[tv, fieldBitOffset, fieldBits, bitsForType]]]]; }; -- END BuildEmbeddedTV RTTypesPrivate.RecordComponentISEI[UnderType[type], index, BuildEmbeddedTV]; RETURN[argsTV]; }; -- END ~catch OR domainOrRange = Range [world: world, message: message] _ RemoteSignalValues[tv]; SELECT TRUE FROM Size[type] = 1 => { ws: WordSequence = NEW[WordSequenceRecord[1]]; ws[0] _ LOOPHOLE[message, CARDINAL]; argsTV _ NEW[TypedVariableRec _ [referentType: [type], head: tvr.head, status: const, field: constant[value: ws]]] }; IsRemote[tv] => argsTV _ NEW[TypedVariableRec _ [referentType: [type], head: [remotePointer [remotePointer: [world: world, worldIncarnation: CurrentIncarnation[world], ptr: Long[world: world, addr: message]]]], status: readOnly, field: entire[]]] ENDCASE => argsTV _ NEW[TypedVariableRec _ [referentType: [type], head: [pointer[ptr: LONG[LOOPHOLE[message, POINTER]]]], status: readOnly, field: entire[]]]; RETURN[IndexToTV[argsTV, index]]; }; -- end ArgOrResult EnclosingBody: PUBLIC SAFE PROC [tv: TV--localFrame--] RETURNS [TV--localFrame--] = TRUSTED { IF IsRemote[tv] THEN { stb: SymbolTableBase = AcquireSTBFromRemoteGFH [[world: GetWorld[tv], worldIncarnation: CurrentIncarnation[GetWorld[tv]], gfh: LOOPHOLE[GetRemoteFrameHeader[RemoteFHFromTV[tv]].accesslink, WorldVM.ShortAddress]]]; rtr: REF TypedVariableRec _ NARROW[tv ! UNWIND => ReleaseSTB[stb]]; bti: BodyIndex; evalStack: WordSequence; isCatchFrame: BOOL; remoteFH: RemoteFrameHandle _ nilRemoteFrameHandle; contextPC: BOOL; level: BlockContextLevel; return: BOOL; WITH th: rtr.head SELECT FROM remoteFH => { bti _ th.bti; evalStack _ th.evalStack; isCatchFrame _ th.isCatchFrame; remoteFH _ th.remoteFrameHandle; contextPC _ th.contextPC; return _ th.return; }; ENDCASE => { ReleaseSTB[stb]; RaiseClassError[tv]; }; IF NullBTI[bti] THEN { IF isCatchFrame THEN { rfh: RemoteFrameHandle = RemoteFHFromTV[tv]; rgfh: WorldVM.ShortAddress _ LOOPHOLE[GetRemoteFrameHeader[rfh].accesslink]; bti _ SmallestBTIFromRemoteFH[rfh, stb, contextPC ! UNWIND => ReleaseSTB[stb]]; IF IsRootBTI[bti] THEN {ReleaseSTB[stb]; RETURN[NIL]}; -- not in the scope of any locals IF GetRemoteFrameHeader[remoteFH].staticlink = NIL THEN ReallyNastyError[]; tv _ TVForRemoteFrame [[world: remoteFH.world, worldIncarnation: CurrentIncarnation[remoteFH.world], fh: LOOPHOLE[GetRemoteFrameHeader[remoteFH].staticlink - PrincOps.localbase, WorldVM.ShortAddress]]]; UNTIL IsBodyEncloser[er: tv, ee: bti, stb: stb] DO rmtFH: RemoteFrameHandle _ RemoteFHFromTV[tv]; IF LOOPHOLE[GetRemoteFrameHeader[rmtFH].accesslink, WorldVM.ShortAddress] # rgfh THEN {ReleaseSTB[stb]; ERROR}; IF GetRemoteFrameHeader[rmtFH].staticlink = NIL THEN ReallyNastyError[]; tv _ TVForRemoteFrame [[world: rmtFH.world, worldIncarnation: CurrentIncarnation[rmtFH.world], fh: LOOPHOLE[GetRemoteFrameHeader[rmtFH].staticlink - PrincOps.localbase, WorldVM.ShortAddress]]]; ENDLOOP; rtr _ NARROW[tv, REF TypedVariableRec]; WITH th: rtr.head SELECT FROM remoteFH => { IF bti = th.bti THEN RETURN[tv]; evalStack _ NIL; -- NOTE isCatchFrame _ th.isCatchFrame; return _ th.return; contextPC _ th.contextPC; }; ENDCASE => ERROR; ReleaseSTB[stb]; RETURN[NEW[TypedVariableRec _ [referentType: [fhType], head: [remoteFH[remoteFrameHandle: RemoteFHFromTV[tv], evalStack: evalStack, bti: bti, isCatchFrame: isCatchFrame, return: return, contextPC: contextPC]], status: mutable, field: entire[]]]]; } ELSE {ReleaseSTB[stb]; RETURN[NIL]} -- either no symbols or no locals }; -- end IF NullBTI[bti] IF CallableBTI[stb, bti] THEN IF (WITH BodyLevel[stb, bti] SELECT FROM -- TRUE => not a nested procedure t: BlockContextLevel.x => t.e <= bx.outerContextLevel, t: BlockContextLevel.y => t.e <= by.outerContextLevel, ENDCASE => ERROR) THEN {ReleaseSTB[stb]; RETURN[NIL]} ELSE { ReleaseSTB[stb]; IF GetRemoteFrameHeader[remoteFH].staticlink = NIL THEN ReallyNastyError[]; RETURN [TVForRemoteFrame [[world: remoteFH.world, worldIncarnation: CurrentIncarnation[remoteFH.world], fh: LOOPHOLE[GetRemoteFrameHeader[remoteFH].staticlink - PrincOps.localbase, WorldVM.ShortAddress]]]]; }; level _ BodyLevel[stb, bti]; bti _ ParentBody[stb, bti]; -- A Callable bt entry also describes the outer block locals IF IsRootBTI[bti] THEN bti _ nullBodyIndex; IF isCatchFrame AND (NOT NullBTI[bti]) AND level # BodyLevel[stb, bti] THEN { ReleaseSTB[stb]; -- we no longer need the stb IF GetRemoteFrameHeader[remoteFH].staticlink = NIL THEN ReallyNastyError[]; tv _ TVForRemoteFrame [[world: remoteFH.world, worldIncarnation: CurrentIncarnation[remoteFH.world], fh: LOOPHOLE[GetRemoteFrameHeader[remoteFH].staticlink- PrincOps.localbase, WorldVM.ShortAddress]]]; rtr _ NARROW[tv, REF TypedVariableRec]; WITH th: rtr.head SELECT FROM remoteFH => { IF bti = th.bti THEN RETURN[tv]; evalStack _ NIL; -- NOTE isCatchFrame _ th.isCatchFrame; return _ th.return; contextPC _ th.contextPC; }; ENDCASE => ERROR } ELSE ReleaseSTB[stb]; RETURN[NEW[TypedVariableRec _ [referentType: [fhType], head: [remoteFH[remoteFrameHandle: RemoteFHFromTV[tv], evalStack: evalStack, bti: bti, isCatchFrame: isCatchFrame, return: return, contextPC: contextPC]], status: mutable, field: entire[]]]]; } ELSE { stb: SymbolTableBase = AcquireSTBFromGFH[FHFromTV[tv].accesslink]; rtr: REF TypedVariableRec _ NARROW[tv ! UNWIND => ReleaseSTB[stb]]; bti: BodyIndex; evalStack: POINTER TO PrincOps.StateVector; isCatchFrame: BOOL; contextPC: BOOL; level: BlockContextLevel; return: BOOL; WITH th: rtr.head SELECT FROM fh => { bti _ th.bti; evalStack _ th.evalStack; isCatchFrame _ th.isCatchFrame; contextPC _ th.contextPC; return _ th.return; }; ENDCASE => { ReleaseSTB[stb]; RaiseClassError[tv]; }; IF NullBTI[bti] THEN { IF isCatchFrame THEN { fh: PrincOps.FrameHandle = FHFromTV[tv]; gfh: PrincOps.GlobalFrameHandle _ fh.accesslink; bti _ SmallestBTIFromFH[fh, stb, contextPC ! UNWIND => ReleaseSTB[stb]]; IF IsRootBTI[bti] THEN {ReleaseSTB[stb]; RETURN[NIL]}; -- not in the scope of any locals IF fh.staticlink = NIL THEN ReallyNastyError[]; tv _ TVForFrame[LOOPHOLE[fh.staticlink - PrincOps.localbase, PrincOps.FrameHandle]]; UNTIL IsBodyEncloser[er: tv, ee: bti, stb: stb] DO IF FHFromTV[tv].accesslink # gfh THEN {ReleaseSTB[stb]; ERROR}; IF FHFromTV[tv].staticlink = NIL THEN ReallyNastyError[]; tv _ TVForFrame[LOOPHOLE[FHFromTV[tv].staticlink - PrincOps.localbase, PrincOps.FrameHandle]]; ENDLOOP; rtr _ NARROW[tv, REF TypedVariableRec]; WITH th: rtr.head SELECT FROM fh => { IF bti = th.bti THEN RETURN[tv]; evalStack _ NIL; -- NOTE isCatchFrame _ th.isCatchFrame; return _ th.return; contextPC _ th.contextPC; }; ENDCASE => ERROR; ReleaseSTB[stb]; RETURN[NEW[TypedVariableRec _ [referentType: [fhType], head: [fh[fh: FHFromTV[tv], evalStack: evalStack, bti: bti, isCatchFrame: isCatchFrame, return: return, contextPC: contextPC]], status: mutable, field: entire[]]]]; } ELSE {ReleaseSTB[stb]; RETURN[NIL]} -- either no symbols or no locals }; -- end IF NullBTI[bti] IF CallableBTI[stb, bti] THEN IF (WITH BodyLevel[stb, bti] SELECT FROM -- TRUE => not a nested procedure t: BlockContextLevel.x => t.e <= bx.outerContextLevel, t: BlockContextLevel.y => t.e <= by.outerContextLevel, ENDCASE => ERROR) THEN {ReleaseSTB[stb]; RETURN[NIL]} ELSE { -- this is a frame for a nested procedure ReleaseSTB[stb]; IF FHFromTV[tv].staticlink = NIL THEN ReallyNastyError[]; RETURN[TVForFrame[LOOPHOLE[FHFromTV[tv].staticlink - PrincOps.localbase, PrincOps.FrameHandle]]]; }; level _ BodyLevel[stb, bti]; bti _ ParentBody[stb, bti]; -- A Callable bt entry also describes the outer block locals IF IsRootBTI[bti] THEN bti _ nullBodyIndex; IF isCatchFrame AND (NOT NullBTI[bti]) AND level # BodyLevel[stb, bti] THEN { ReleaseSTB[stb]; -- we no longer need the stb IF FHFromTV[tv].staticlink = NIL THEN ReallyNastyError[]; tv _ TVForFrame[LOOPHOLE[FHFromTV[tv].staticlink - PrincOps.localbase, PrincOps.FrameHandle]]; rtr _ NARROW[tv, REF TypedVariableRec]; WITH th: rtr.head SELECT FROM fh => { IF bti = th.bti THEN RETURN[tv]; evalStack _ NIL; -- NOTE isCatchFrame _ th.isCatchFrame; return _ th.return; contextPC _ th.contextPC; }; ENDCASE => ERROR } ELSE ReleaseSTB[stb]; RETURN[NEW[TypedVariableRec _ [referentType: [fhType], head: [fh[fh: FHFromTV[tv], evalStack: evalStack, bti: bti, isCatchFrame: isCatchFrame, return: return, contextPC: contextPC]], status: mutable, field: entire[]]]]; }; -- end local case of EnclosingBody }; -- end EnclosingBody Locals: PUBLIC SAFE PROC [tv: TV] RETURNS [TV _ NIL] = TRUSTED { rtr: REF TypedVariableRec _ NARROW[tv]; IF tv # NIL THEN { bti: BodyIndex; type: Type _ nullType; inner: PROC [stb: SymbolTableBase] = { IF NullBTI[bti] OR IsRootBTI[bti] OR NullSEI[BodyType[stb, bti]] THEN RETURN; type _ AcquireType[stb, BodyType[stb, bti]]; }; IF IsRemote[tv] THEN { fh: RemoteFrameHandle = RemoteFHFromTV[tv]; IF fh = nilRemoteFrameHandle THEN RETURN[NIL]; bti _ (WITH th: rtr.head SELECT FROM remoteFH => th.bti, ENDCASE => nullBodyIndex); OuterFromRemoteGFH[ [world: fh.world, worldIncarnation: CurrentIncarnation[fh.world], gfh: LOOPHOLE[GetRemoteFrameHeader[fh].accesslink, WorldVM.ShortAddress]], inner]; } ELSE { fh: PrincOps.FrameHandle = FHFromTV[tv]; IF fh = NIL THEN RETURN[NIL]; bti _ (WITH th: rtr.head SELECT FROM fh => th.bti, ENDCASE => nullBodyIndex); OuterFromGFH[fh.accesslink, inner]; }; IF type # nullType THEN RETURN[NEW[TypedVariableRec _ [referentType: [type], head: rtr.head, status: mutable, field: entire[]]]]; }; }; DynamicParent: PUBLIC SAFE PROC [tv: TV--localFrame--] RETURNS [TV _ NIL] = TRUSTED { IF IsRemote[tv] THEN { remoteFH: RemoteFrameHandle = RemoteFHFromTV[tv]; cl: PrincOps.ControlLink; IF remoteFH.fh = 0 THEN RETURN[NIL]; cl _ AMProcessBasic.ReturnLink [remoteFH.world, LOOPHOLE[remoteFH.fh, PrincOps.FrameHandle]]; IF cl.proc OR cl.indirect THEN RETURN[NIL] ELSE RETURN[TVForRemoteFrame [[world: remoteFH.world, worldIncarnation: CurrentIncarnation[remoteFH.world], fh: LOOPHOLE[cl.frame, WorldVM.ShortAddress]]]]; } ELSE { fh: PrincOps.FrameHandle _ FHFromTV[tv]; cl: PrincOps.ControlLink; IF fh = NIL THEN RETURN[NIL]; cl _ AMProcessBasic.ReturnLink[WorldVM.LocalWorld[], fh]; IF cl.proc OR cl.indirect THEN RETURN[NIL] ELSE RETURN[TVForFrame[cl.frame]]; }; }; Globals: PUBLIC SAFE PROC [tv: TV] RETURNS [TV _ NIL] = TRUSTED { rtr: REF TypedVariableRec _ NARROW[tv]; IF tv # NIL THEN { type: Type _ nullType; inner: PROC [stb: SymbolTableBase] = { type _ AcquireType[stb, RootBodyType[stb]]; }; IF IsRemote[tv] THEN { gfh: RemoteGlobalFrameHandle _ RemoteGFHFromTV[tv]; IF gfh # nilRemoteGlobalFrameHandle THEN OuterFromRemoteGFH[gfh, inner]; RETURN[NEW[TypedVariableRec _ [referentType: [type], head: rtr.head, status: mutable, field: entire[]]]]; } ELSE { gfh: PrincOps.GlobalFrameHandle _ GFHFromTV[tv]; IF gfh = NIL THEN RETURN[NIL]; LoadState.local.Acquire[]; type _ LoadState.local.GlobalFrameToType[gfh ! UNWIND => LoadState.local.Release[]]; LoadState.local.Release[]; IF type = nullType THEN OuterFromGFH[gfh, inner]; }; RETURN[NEW[TypedVariableRec _ [referentType: [type], head: rtr.head, status: mutable, field: entire[]]]]; }; }; IsBodyEncloser: PROC [er: TV, ee: BodyIndex, stb: SymbolTableBase] RETURNS [ans: BOOL _ FALSE] = { rtr: REF TypedVariableRec _ NARROW[er]; WITH th: rtr.head SELECT FROM fh => {-- does th.bti enclose ee? WITH stb SELECT FROM t: SymbolTableBase.x => FOR bti: bx.BodyIndex _ NARROW[th.bti, BodyIndex.x].e, t.e.SonBti[bti] UNTIL bti = bx.nullBodyIndex DO IF bti = NARROW[ee, BodyIndex.x].e THEN RETURN[TRUE]; ENDLOOP; t: SymbolTableBase.y => FOR bti: by.BodyIndex _ NARROW[th.bti, BodyIndex.y].e, t.e.SonBti[bti] UNTIL bti = by.nullBodyIndex DO IF bti = NARROW[ee, BodyIndex.y].e THEN RETURN[TRUE]; ENDLOOP; ENDCASE => ERROR; }; remoteFH => {-- does th.bti enclose ee? WITH stb SELECT FROM t: SymbolTableBase.x => FOR bti: bx.BodyIndex _ NARROW[th.bti, BodyIndex.x].e, t.e.SonBti[bti] UNTIL bti = bx.nullBodyIndex DO IF bti = NARROW[ee, BodyIndex.x].e THEN RETURN[TRUE]; ENDLOOP; t: SymbolTableBase.y => FOR bti: by.BodyIndex _ NARROW[th.bti, BodyIndex.y].e, t.e.SonBti[bti] UNTIL bti = by.nullBodyIndex DO IF bti = NARROW[ee, BodyIndex.y].e THEN RETURN[TRUE]; ENDLOOP; ENDCASE => ERROR; }; ENDCASE => ERROR; }; AcquireBTIFromFH: PROC [fh: PrincOps.FrameHandle, contextPC: BOOL] RETURNS [isCatchFrame: BOOL _ FALSE, bti: BodyIndex _ nullBodyIndex] = { inner: PROC [stb: SymbolTableBase] = { bti _ SmallestBTIFromFH[fh, stb, contextPC]; [isCatchFrame, bti] _ IsCatchFrame[fh, bti]; }; OuterFromGFH[fh.accesslink, inner]; }; SmallestBTIFromFH: PROC [fh: PrincOps.FrameHandle, stb: SymbolTableBase, contextPC: BOOL] RETURNS [bti: BodyIndex] = { start: PrincOps.BytePC; epn: CARDINAL; framePC: PrincOps.BytePC = [(fh.pc - (IF contextPC THEN 0 ELSE 1))]; [epn, start] _ GetEp[framePC, fh.accesslink, stb]; bti _ ConvertCbti[ base: stb, pc: framePC, start: start, lastBti: LOOPHOLE[GetCBTI[stb, epn], BodyIndex] ]; }; SmallestBTIFromRemoteFH: PROC [rfh: RemoteFrameHandle, stb: SymbolTableBase, contextPC: BOOL] RETURNS [bti: BodyIndex] = { start: PrincOps.BytePC; epn: CARDINAL; remoteFrame: REF PrincOps.Frame = GetRemoteFrameHeader[rfh]; framePC: PrincOps.BytePC = [(remoteFrame.pc - (IF contextPC THEN 0 ELSE 1))]; [epn, start] _ GetRemoteEp[ pc: framePC, gf: [world: rfh.world, worldIncarnation: CurrentIncarnation[rfh.world], gfh: LOOPHOLE[remoteFrame.accesslink, ShortAddress]], stb: stb]; bti _ ConvertCbti[ base: stb, pc: framePC, start: start, lastBti: LOOPHOLE[GetCBTI[stb, epn], BodyIndex]]; }; GetCBTI: PUBLIC PROC [stb: SymbolTableBase, epn: CARDINAL] RETURNS [cbti: CallableBodyIndex] = { IsThisItX: PROC [bti: bx.BodyIndex] RETURNS [stop: BOOL] = { WITH NARROW[stb, SymbolTableBase.x].e.bb[bti] SELECT FROM Callable => RETURN[(NOT inline) AND (epn = entryIndex)]; ENDCASE => RETURN[FALSE]; }; IsThisItY: PROC [bti: by.BodyIndex] RETURNS [stop: BOOL] = { WITH NARROW[stb, SymbolTableBase.y].e.bb[bti] SELECT FROM Callable => RETURN[(NOT inline) AND (epn = entryIndex)]; ENDCASE => RETURN[FALSE]; }; bi: BodyIndex = WITH stb SELECT FROM t: SymbolTableBase.x => [x[t.e.EnumerateBodies[bx.rootBodyIndex, IsThisItX]]], t: SymbolTableBase.y => [y[t.e.EnumerateBodies[by.rootBodyIndex, IsThisItY]]], ENDCASE => ERROR; RETURN[LOOPHOLE[bi, CallableBodyIndex]]; }; ConvertCbti: PUBLIC PROC [lastBti: BodyIndex, pc, start: PrincOps.BytePC, base: SymbolTableBase] RETURNS [bti: BodyIndex] = { WITH base SELECT FROM t: SymbolTableBase.x => RETURN[[x[ConvertCbtiX[NARROW[lastBti, BodyIndex.x].e, pc, start, t.e]]]]; t: SymbolTableBase.y => RETURN[[y[ConvertCbtiY[NARROW[lastBti, BodyIndex.y].e, pc, start, t.e]]]]; ENDCASE => ERROR; }; ConvertCbtiX: PROC [lastBti: bx.BodyIndex, pc, start: PrincOps.BytePC, base: bx.SymbolTableBase] RETURNS [bti: bx.BodyIndex] = { bodyStart: PrincOps.BytePC; bti _ lastBti; DO FOR lastBti _ base.SonBti[bti], base.SiblingBti[lastBti] UNTIL lastBti = bx.nullBodyIndex DO WITH body: base.bb[lastBti] SELECT FROM Callable => LOOP; Other => { bodyStart _ [start + body.relOffset]; WITH body.info SELECT FROM External => IF pc IN [bodyStart..bodyStart+bytes) THEN {bti _ lastBti; EXIT}; ENDCASE; }; ENDCASE; REPEAT FINISHED => RETURN ENDLOOP; ENDLOOP; }; ConvertCbtiY: PROC [lastBti: by.BodyIndex, pc, start: PrincOps.BytePC, base: by.SymbolTableBase] RETURNS [bti: by.BodyIndex] = { bodyStart: PrincOps.BytePC; bti _ lastBti; DO FOR lastBti _ base.SonBti[bti], base.SiblingBti[lastBti] UNTIL lastBti = by.nullBodyIndex DO WITH body: base.bb[lastBti] SELECT FROM Callable => LOOP; Other => { bodyStart _ [start + body.relOffset]; WITH body.info SELECT FROM External => IF pc IN [bodyStart..bodyStart+bytes) THEN {bti _ lastBti; EXIT}; ENDCASE; }; ENDCASE; REPEAT FINISHED => RETURN ENDLOOP; ENDLOOP; }; GetEp: PUBLIC PROC [pc: PrincOps.BytePC, gf: PrincOps.GlobalFrameHandle, stb: SymbolTableBase] RETURNS [ep: EVRange, start: PrincOps.BytePC] = { FindMaxEI: PROC RETURNS [max: EVRange] = { GetMaxX: PROC [bti: bx.BodyIndex] RETURNS [stop: BOOL] = { WITH NARROW[stb, SymbolTableBase.x].e.bb[bti] SELECT FROM Callable => IF ~inline THEN max _ MAX[max, entryIndex]; ENDCASE; RETURN[FALSE]; }; GetMaxY: PROC [bti: by.BodyIndex] RETURNS [stop: BOOL] = { WITH NARROW[stb, SymbolTableBase.y].e.bb[bti] SELECT FROM Callable => IF ~inline THEN max _ MAX[max, entryIndex]; ENDCASE; RETURN[FALSE]; }; max _ 0; WITH stb SELECT FROM t: SymbolTableBase.x => [] _ t.e.EnumerateBodies[bx.rootBodyIndex, GetMaxX]; t: SymbolTableBase.y => [] _ t.e.EnumerateBodies[by.rootBodyIndex, GetMaxY]; ENDCASE => ERROR; }; diff: CARDINAL _ LAST[CARDINAL]; anyProcedure: BOOL _ FALSE; FOR i: EVRange IN [0..FindMaxEI[]] DO Card: PROC [pc: PrincOps.BytePC] RETURNS [CARDINAL] = INLINE {RETURN[LOOPHOLE[pc, CARDINAL]]}; last: PrincOps.BytePC _ GetPc[gf, i]; IF Card[last] > Card[pc] THEN LOOP; IF Card[pc] - Card[last] > diff THEN LOOP; diff _ Card[pc] - Card[last]; ep _ i; start _ last; anyProcedure _ TRUE; ENDLOOP; IF ~anyProcedure THEN ERROR; -- SIGNAL NotInAnyProcedure; }; GetPc: PUBLIC PROC [gf: PrincOps.GlobalFrameHandle, i: EVRange] RETURNS [PrincOps.BytePC] = { codeBase: LONG POINTER TO PrincOps.CSegPrefix = PrincOpsUtils.Codebase[gf]; wpc: CARDINAL = codeBase.entry[i].initialpc; -- GROAN RETURN[LOOPHOLE[wpc*2, PrincOps.BytePC]]; }; IsCatchFrame: PROC [frame: PrincOps.FrameHandle, bti: BodyIndex] RETURNS [BOOL, BodyIndex] = { L0Frame: PrincOps.FrameHandle; -- will be the frame that encloses the catch frame nextFrame: PrincOps.FrameHandle; tr: REF TypedVariableRec; IF frame = NIL THEN RETURN[FALSE, bti]; nextFrame _ AMProcessBasic.ReturnLink[WorldVM.LocalWorld[], frame].frame; IF nextFrame = NIL THEN RETURN[FALSE, bti]; IF nextFrame.accesslink # sigGF OR ~nextFrame.mark THEN RETURN[FALSE, bti]; IF frame.staticlink = NIL THEN ReallyNastyError[]; L0Frame _ LOOPHOLE[frame.staticlink - PrincOps.localbase, PrincOps.FrameHandle]; IF frame.accesslink # L0Frame.accesslink THEN RETURN[FALSE, bti]; tr _ NARROW[TVForFrame[L0Frame], REF TypedVariableRec]; WITH hd: tr.head SELECT FROM fh => IF bti = hd.bti THEN bti _ IF bti.brand = x THEN [x[bx.nullBodyIndex]] ELSE [y[by.nullBodyIndex]]; ENDCASE => ERROR; RETURN[TRUE, bti]; }; RaiseClassError: PROC [tv: TV] = { ERROR AMTypes.Error[reason: typeFault, type: AMTypes.TVType[tv]]; }; ReallyNastyError: PROC = { ERROR; }; END. RTTypedFramesImpl.Mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Russ Atkinson, February 11, 1985 7:56:08 pm PST Paul Rovner, November 9, 1983 10:49 pm TYPES CONSTANTS PUBLIC PROCEDURES raises typeFault all such tvs have the same (distinguished) type: fhType raises typeFault raises typeFault raises typeFault local case Note: the current method for detecting started rests with the 'out' bit in the codebase, not with the started bit, although we will take either. last time there were no symbols for this turkey returns BTNull if still no symbols start proc frame non-remote localFrame TV arg to Procedure XXX be careful about access via assign to RC variables that appear to be in a local frame (startproc) but really live in the GF. Also remote case returns BTNull if still no symbols here with bti # nullBodyIndex search up thru enclosing blocks till a callable one IF entryIndex = 0 THEN ERROR Error[reason: typeFault, type: TVType[tv]]; going up from a block or a body inside a startproc. here if the local frame has no enclosing callable body. This can't happen. It is possible that when last sampled, bti = nullBodyIndex, but that the symbols are now available. So, we try to examine said symbols again. In this case, we don't care that thngs are expensive, so we use Procedure to do our dirty work. returns a signal type if tv is for a catch frame, a procedure type if tv is for a local frame, raises TypeFault otherwise. find the specified element in the frame, create a TV for it bit offset of the field within the local frame Begin Here gotta do something different if this is an arg to a catch phrase message is either a pointer to a long arg record OR a single word value maybe NIL NOTE: if tv represents a block within a catch phrase, EnclosingBody may return the wrong context; i.e., the one enclosing the catch phrase. This won't come up if there is no block in the catch phrase at all; TVForFrame will detect it and do the right thing. It's harder to do the right thing here. The right solution is to put catch phrases in the body table!!! static nesting level, associated with a CTX (optimization: blocks, instead of counting up, get level of enclosing proc). 0 (lZ)=> off in the heap (not part of a frame...lifetime determined by some sort of runtime storage management, e.g. records, ctx for names of guys in an emum); 1 (lG) => global frame, outermost proc 2 (lL) and >2 => nested procedure. catch phrase in main prog would have a level of 2 (tho these are not recorded, because there are not symbol table entries for catch phrases. a fh tv will have NullBTI[bti] if there are no symbols for its referent or if it represents a frame for a startproc or catch phrase at a point outside the scope of locals get the bti of the smallest body that encloses the PC (if it's rootBodyIndex then RETURN[NIL]). Verify that this body is a body contained (not necessarily properly) within a frame somewhere up the static link. Return a tv for such a frame. starting with the frame of the most recent instance of the smallest enclosing static parent of the catch frame, search up the static chain to find the first frame that encloses the catch frame look up the static chain to find an encloser of bti (bti # rootBodyIndex) => one better exist Easy if we already have the right bti, otherwise get the new value of isCatchFrame No more enclosing blocks: this one is callable and not a catch frame this is a frame for a nested procedure means either that tv represents a frame for a startproc or catch phrase at a place outside the scope of locals. When the level changes inside of a catch phrase then we have to go through the static link (local 0) to get to the frame that corresponds to this bti. The static link points at local 0, not the frame base (=> subtract localbase). Easy if we already have the right bti, otherwise get the new value of isCatchFrame local case of EnclosingBody static nesting level, associated with a CTX (optimization: blocks, instead of counting up, get level of enclosing proc). 0 (lZ)=> off in the heap (not part of a frame...lifetime determined by some sort of runtime storage management, e.g. records, ctx for names of guys in an emum); 1 (lG) => global frame, outermost proc 2 (lL) and >2 => nested procedure. catch phrase in main prog would have a level of 2 (tho these are not recorded, because there are not symbol table entries for catch phrases. a fh tv will have NullBTI[bti] if there are no symbols for its referent or if it represents a frame for a startproc or catch phrase at a point outside the scope of locals get the bti of the smallest body that encloses the PC (if it's rootBodyIndex then RETURN[NIL]). Verify that this body is a body contained (not necessarily properly) within a frame somewhere up the static link. Return a tv for such a frame. starting with the frame of the most recent instance of the smallest enclosing static parent of the catch frame, search up the static chain to find the first frame that encloses the catch frame look up the static chain to find an encloser of bti (bti # rootBodyIndex) => one better exist Easy if we already have the right bti, otherwise get the new value of isCatchFrame No more enclosing blocks: this one is callable and not a catch frame means either that tv represents a frame for a startproc or catch phrase at a place outside the scope of locals. When the level changes inside of a catch phrase then we have to go through the static link (local 0) to get to the frame that corresponds to this bti. The static link points at local 0, not the frame base (=> subtract localbase). Easy if we already have the right bti, otherwise get the new value of isCatchFrame Cases: normal, startproc, block in startproc, catch frame, block in catch frame, catch frame in startproc. Possibly no symbols. all cases below can raise Error[noSymbols] normal: returns a vanilla-flavored (maybe callable) bti catch frame: returns a non-callable bti or nullBodyIndex (if outside scope of locals) startproc: returns a vanilla-flavored bti, maybe rootBodyIndex if fh is for a catch phrase, bti might be for a proc that contains it. if epn = 0 then this is a frame for the startproc or for a catchframe in the startproc if epn = 0 then this is a frame for the startproc or for a catchframe in the startproc finds the cbti for the specified entrypoint finds the bti for the smallest enclosing block finds the entrypoint index and its start pc for the proc containing the specified pc. BEWARE that if the pc is in a catch phrase, this returns the epn for the statically enclosing procedure of the catch phrase. body of GetEp begins here finds the start (byte) pc for the specified entrypoint index and GF return FALSE if caller is not the signaller detect situation where catch frame has no locals, thus no body table entry. return nullBodyIndex if isCatchFrame and it has no locals ส-t– "cedar" style˜codešœ™Kšœ ฯmœ1™Kšœžœ˜กKšœžœถ˜ะKšœ žœžœ˜Kšœ žœ#˜4Kšœžœ=˜J—K˜šœž˜Kšžœฆ˜ญKšžœ"˜)Kšœžœžœส˜ึ—K™šœ™Kšœ žœ˜(—K™šœ ™ šœ$žœ˜-Kšœžœ žœ)˜W——K™Kšœ™™šฯn œžœžœžœžœžœžœžœžœ˜DKšœ™šžœž˜"Kšœžœ˜Kš œžœžœžœžœžœžœ˜EKšžœ˜—Kš žœžœžœžœžœžœ˜:Kšœ˜—K˜šŸ œžœžœ(žœžœžœ žœžœ žœžœžœžœžœ˜ฐKšœ˜Kšœžœžœ˜Kš žœžœžœžœžœ˜šœ4˜4Kšœ žœžœžœ˜J—šžœžœ˜šœ˜šœ˜šœ!˜!KšœO˜O——Kšœ˜Kšœ˜Kšœ˜——Kšœ˜—K™š Ÿœžœžœžœžœžœ˜GKšœ7™7Kšœ™Kš žœžœžœžœžœ˜šžœžœž˜šœžœ˜šžœžœž˜Kšœžœ ˜Kšžœžœžœ˜——Kšžœžœžœ˜—Kšžœ˜!Kšœ˜—K˜š Ÿœžœžœ#žœžœžœ˜Všžœžœžœ˜šžœžœ˜KšœW˜W——Kšœ˜—K™š Ÿ œžœžœžœžœžœ˜NKšœ™Kš žœžœžœžœžœ˜šžœžœž˜šœžœ˜šžœžœž˜Kšœžœ ˜Kšžœ˜——Kšžœ˜—Kšœ˜Kšœ˜—K™šŸ œžœžœžœžฯcœžœž œžœ˜jKšœ™šžœžœ˜Kšœ˜Kšœ:˜:šžœž˜šœ˜Kšœ+˜+Kšžœ žœžœžœ˜šœ˜Kšœ˜Kšœ0˜0Kšœžœ=˜K—Kšœ˜—šœ˜Kšœ"˜"Kš žœ žœžœžœžœžœ˜>šœ˜Kšœ˜Kšœ0˜0Kšœžœ<˜J—Kšœ˜—šœ˜Kšœ&˜&šžœ žœžœ˜.Kšžœžœ žœ ˜(Kš žœžœ žœžœžœžœ˜;Kš žœžœ žœžœžœžœ˜˜K——Kšžœ-˜2Kšœ˜—Kšœ˜—Kšœ˜———Kšžœ˜—Kšžœžœ˜)Kšœ˜Kšžœ žœžœžœ˜šœ˜šœ˜Kšœ/˜/Kšœžœ>˜K——šžœ!žœž˜9šžœžœ˜Kšœžœ*˜Lšœ2˜2Kšœžœ˜@—Kšžœžœ˜+Kšœ™šœ˜šœ˜šœ˜Kšœ/˜/Kšœžœ;˜H—Kšœ&˜&——Kšœžœ˜*Kšœ˜Kšžœ:žœ ˜RKšœ˜—Kšžœ˜—Kšœ˜Kšžœžœ˜ Kšœ˜——šžœ˜Kšœ)™)Kšœ˜Kšœžœ˜Kšœ˜Kšœ˜Kš žœžœžœžœžœ˜Kšœžœ˜šžœžœž˜šœ˜šžœ˜Kšžœ˜šžœ˜Kšœ ˜ Kšœe™eKšœ+™+Kšžœ $˜5šžœ˜Kšœ˜Kšœ3žœžœ˜MKšœ"™"šžœžœ˜šžœ˜Kšœ2˜2Kšœ ˜ Kšžœžœ˜,Kšœ˜—KšžœžœD˜N—Kšœ˜—Kšœ˜———Kšžœ˜—Kšœ™Kšœ˜Kš žœžœžœžœžœ˜Kšœ'˜'Kšœ3™3šžœ!žœž˜9šžœžœ˜Kšœžœ*˜Lšœ2˜2Kšœžœ˜@—KšœH™HKšœ3™3Kšœ;˜;Kšœžœ˜*Kšœ˜Kš žœ žœžœžœžœžœ˜8Kšœ˜—Kšžœ˜—Kšœ˜Kšœ7™7Kšœ™Kšžœ˜Kšœ˜—Kšœ˜—K˜šŸœžœžœžœž œžœž œžœ˜bšžœ ˜šžœ˜Kšœ ˜ Kšœ˜Kšœ5˜5KšœYžœ˜hKšœ˜—Kš žœžœ žœžœžœžœ˜X——K˜šŸœžœžœžœžœžœžœžœ˜=Kšœ˜šžœž˜šžœžœž˜šœžœ˜Kšœ˜Kšœ žœžœ˜šžœžœž˜Kšœ6˜6Kšœ1˜1Kšžœžœžœ˜—Kšžœžœžœ ˜-Kšœ๏™๏šœ˜Kš œžœžœ žœžœ˜K—Kšžœ ˜K˜—Kšžœ˜——Kšžœžœ˜K˜K˜—šŸœžœžœžœž œžœžœžœ˜bKšžœ!˜'Kšœ˜—K˜šŸœžœžœžœž œžœžœžœ˜`Kšžœ ˜&Kšœ˜—K˜šŸ œžœž œžœžœ žœžœ˜}Kšœ ˜ Kšœžœ˜ Kšœ žœ˜Kšœ ˜ Kšœžœ˜Kšœžœžœ˜'Kšœžœ˜K™Kšœz™zš Ÿœžœžœžœ žœžœ˜[Kšœžœžœ˜'šžœžœž˜šœ˜Kšœ˜Kšœžœžœ žœ˜;Kšœ˜—šœ ˜ Kšœ˜Kšœžœžœ žœ˜;Kšœ˜—Kšžœ˜—Kšœ˜—K˜Kšžœžœžœžœ*˜@Kšœ(˜(Kšžœžœžœ˜6Kšœ˜Kšžœžœžœ˜6šžœžœž˜Kšœžœ˜Kšžœžœ&˜6—Kšžœžœ˜"šžœ˜Kšœ;™;šŸœžœ0˜EKšœ&˜&Kšœ5˜5šœ žœžœ˜šœžœžœž˜Kšœ(žœ$˜RKšœ(žœ$˜RKšžœžœ "˜6——šœ žœ˜šœžœžœž˜Kšœ žœ"˜HKšœ žœ"˜HKšžœžœ ˜,——šœžœ˜šœžœžœž˜Kšœ žœ#˜IKšœ žœ#˜IKšžœžœ˜——Kšœ.™.Kšœ$˜$Kšžœ˜šžœ˜Kšžœžœ˜1šžœ žœ˜$Kšœ˜Kšœ $˜:Kšœ˜Kšœ<˜<—šžœ C˜HKšœ žœ˜Kšœ˜šœ˜šœžœžœž˜Kšœžœ˜$Kšžœžœ˜——Kšœ˜Kšœ=˜=—Kšœ˜—šž˜šœ žœ˜Kšœ˜šœ˜šœžœžœž˜Kšœžœ˜#Kšžœžœ˜——Kšœ žœžœ žœ˜Fšœ˜šœ ˜ KšœN˜N————Kšœ ˜—Kšœ ™ KšœL˜LKšžœ ˜Kšœ &˜*—K™Kšœ@™@Kšœ:˜:KšœG™Gšžœžœž˜šœ˜Kšœžœ˜.Kšœžœ žœ˜$šœ žœ˜šœ˜Kšœ˜Kšœ˜Kšœ˜——Kšœ˜—šœ˜šœ žœ˜šœ˜šœ˜šœ˜šœ˜Kšœ˜Kšœ-˜-Kšœ+˜+———Kšœ˜Kšœ˜———šžœ žœ˜(šœ˜Kšœžœžœ žœ˜8Kšœ˜Kšœ˜———Kšžœ˜!Kšœ ˜—K˜šŸ œžœžœžœž œžœž œžœ˜]Kšœ ™ Kšžœๆ™๊šžœžœ˜šœ.˜.Kšœ˜Kšœ5˜5šœžœ5˜DKšœ˜——Kšœžœžœžœ˜CKšœ˜Kšœ˜Kšœžœ˜Kšœ3˜3Kšœ žœ˜Kšœ˜šœžœ˜ Kšœx™xKšœ ™ Kšœ&™&Kšœ"™"Kšœ™—šžœžœž˜šœ ˜ Kšœ ˜ Kšœ˜Kšœ˜Kšœ ˜ Kšœ˜Kšœ˜Kšœ˜—šžœ˜ Kšœ˜Kšœ˜Kšœ˜—K™Kšœช™ช—šžœžœ˜šžœžœ˜Kšœ๐™๐Kšœ,˜,Kšœžœ'˜LKšœ4žœ˜Oš žœžœžœžœ !˜XKšœภ™ภ—Kšžœ-žœ˜Kšœ˜šœ˜Kšœ5˜5šœžœ*˜6Kšœ.˜.———Kšžœ*˜/Kšœ3™3šžœ˜Kšœ.˜.šžœžœE˜PKšžœžœ˜—Kšœ)™)Kšžœ*žœ˜Hšœ˜šœ˜Kšœ2˜2šœžœ'˜3Kšœ.˜.———Kšžœ˜—Kšœžœžœ˜'šžœžœž˜šœ ˜ KšœR™RKšžœžœžœ˜ Kšœ žœ ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜—Kšžœžœ˜—Kšœ˜šžœžœ˜Kšœ˜šœ˜Kšœ0˜0Kšœ˜Kšœ ˜ Kšœ˜Kšœ˜Kšœ˜—Kšœ˜Kšœ˜—Kšœ˜—Kšžœžœžœ !˜FKšœ ˜—K˜šžœž˜KšœD™Dš žœžœžœžœ !˜KKšœ7˜7Kšœ7˜7Kšœžœžœ˜—Kšžœžœžœ˜#šžœ˜Kšœ&™&Kšœ˜Kšžœ-žœžœ˜Kšž˜šœ˜Kšœ˜Kšœ7˜7šœžœ*˜8Kšœ3˜3———Kšœ˜——Kšœ˜Kšœ <˜YKšžœžœ˜,Kšœo™ošžœžœžœžœ˜Fšžœ˜Kšœๅ™ๅKšœ ˜-Kšžœ-žœžœ˜Kšœ˜šœ˜Kšœ5˜5šœžœ?˜KKšœ˜———Kšœžœžœ˜'šžœžœž˜šœ ˜ KšœR™RKšžœžœžœ˜ Kšœ žœ ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜—Kšžœž˜—Kšœ˜—Kšžœ˜—šžœžœ˜Kšœ˜šœ˜Kšœ0˜0Kšœ˜Kšœ ˜ Kšœ˜Kšœ˜Kšœ˜—Kšœ˜Kšœ˜—Kšœ˜—šžœ˜Kšœ™KšœB˜BKšœžœžœžœ˜CKšœ˜Kšœ žœžœ˜+Kšœžœ˜Kšœ žœ˜Kšœ˜šœžœ˜ Kšœx™xKšœ ™ Kšœ&™&Kšœ"™"Kšœ™—šžœžœž˜šœ˜Kšœ ˜ Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜—šžœ˜ Kšœ˜Kšœ˜Kšœ˜——Kšœช™ชKšžœ ˜šžœ˜šžœžœ˜Kšœ๐™๐Kšœ(˜(Kšœ0˜0Kšœ-žœ˜HKš žœžœžœžœ !˜XKšœภ™ภKšžœžœžœ˜/Kšœžœ<˜TKšžœ*˜/Kšœ3™3šžœ˜Kšžœžœžœ˜?Kšœ)™)Kšžœžœ˜9šœžœ.˜FKšœ˜—Kšžœ˜—Kšœžœžœ˜'šžœžœž˜šœ˜KšœR™RKšžœžœžœ˜ Kšœ žœ ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜—Kšžœžœ˜—Kšœ˜šžœžœ˜Kšœ˜šœ˜šœ˜Kšœ˜Kšœ ˜ Kšœ˜Kšœ˜Kšœ˜——Kšœ˜Kšœ˜—Kšœ˜—Kšžœžœžœ !˜FKšœ ˜—šžœž˜KšœD™Dš žœžœžœžœ !˜KKšœ7˜7Kšœ7˜7Kšœžœžœ˜—Kšžœžœžœ˜#šžœ )˜0Kšœ˜Kšžœžœ˜9Kšžœ žœG˜aKšœ˜——Kšœ˜Kšœ <˜YKšžœžœ˜,Kšœo™oKšžœžœžœžœ˜Fšžœ˜Kšœๅ™ๅKšœ ˜-Kšžœžœ˜9KšœžœF˜^Kšœžœžœ˜'šžœžœž˜šœ˜KšœR™RKšžœžœžœ˜ Kšœ žœ ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜—Kšžœž˜—Kšœ˜—Kšžœ˜šžœžœ˜Kšœ˜Kšœ€˜€Kšœ˜Kšœ˜—Kšœ "˜&—Kšœ ˜—K™šŸœžœžœžœžœžœžœžœžœ˜@Kšœžœžœ˜'šžœžœžœ˜Kšœ˜Kšœ˜šœžœ˜&Kš žœžœžœžœžœ˜MKšœ,˜,K˜—šžœ ˜šžœ˜Kšœ+˜+Kšžœžœžœžœ˜.Kš œžœžœžœžœ˜Sšœ˜šœ˜Kšœ/˜/Kšœžœ=˜J—Kšœ˜—Kšœ˜—šžœ˜Kšœ(˜(Kš žœžœžœžœžœ˜Kš œžœžœžœžœ˜MKšœ#˜#Kšœ˜——šžœž˜šžœžœ˜KšœK˜K——K˜—Kšœ˜—K˜šŸ œžœžœžœž œžœžœžœžœ˜Ušžœžœ˜Kšœ1˜1Kšœ˜Kšžœžœžœžœ˜$Kšœ˜Kšœžœ%˜>šžœ žœ ˜Kšžœžœžœ˜šžœžœ˜šœ˜Kšœ5˜5Kšœžœ$˜0———Kšœ˜—šžœ˜Kšœ(˜(Kšœ˜Kš žœžœžœžœžœ˜Kšœ9˜9Kšžœ žœ žœžœžœžœžœ˜MKšœ˜—Kšœ˜—K™šŸœžœžœžœžœžœžœžœžœ˜AKšœžœžœ˜'šžœžœžœ˜Kšœ˜šœžœ˜&Kšœ+˜+K˜—šžœžœ˜Kšœ3˜3Kšžœ"žœ ˜Hšžœžœ˜KšœK˜K—Kšœ˜—šžœ˜Kšœ0˜0Kš žœžœžœžœžœ˜Kšœ˜Kšœ/žœ˜TKšœ˜Kšžœžœ˜1Kšœ˜—šžœžœ˜KšœK˜K—K˜—Kšœ˜—K™š Ÿœžœžœ'žœžœžœ˜bKšœžœžœ˜'šžœžœž˜šœ ˜!šžœžœž˜šœ˜šžœžœ(˜FKšžœ˜Kš žœžœžœžœžœžœ˜8Kšžœ˜——šœ˜šžœžœ(˜FKšžœ˜Kš žœžœžœžœžœžœ˜8Kšžœ˜——Kšžœžœ˜—Kšœ˜—šœ  ˜'šžœžœž˜šœ˜šžœžœ(˜FKšžœ˜Kš žœžœžœžœžœžœ˜8Kšžœ˜——šœ˜šžœžœ(˜FKšžœ˜Kš žœžœžœžœžœžœ˜8Kšžœ˜——Kšžœžœ˜—Kšœ˜—Kšžœžœ˜—Kšœ˜—K™š Ÿœžœ'žœžœž œ%˜‹Kšœ๘™๘šœžœ˜&Kšœ,˜,KšœF™FKšœ,˜,K˜—Kšœ#˜#Kšœ˜—K˜šŸœžœ=žœžœ˜vKšœ˜Kšœžœ˜Kšœ&žœ žœžœ˜DKšœ2˜2KšœV™Všœ˜Kšœ ˜ Kšœ ˜ Kšœ ˜ Kšœ žœ˜/Kšœ˜—Kšœ˜—K˜šŸœžœ;žœžœ˜zKšœ˜Kšœžœ˜Kšœ žœ,˜˜PKšžœ'žœžœžœ˜AKšœK™KKšœžœžœ˜7šžœ žœž˜šœ˜šžœž˜Kšœžœžœžœ˜M——Kšœ9™9Kšžœžœ˜—Kšžœžœ˜Kšœ˜K˜—šŸœžœžœ˜"Kšžœ<˜AK˜K˜—šŸœžœ˜Kšžœ˜K˜—K˜—Kšžœ˜K˜—…—‚สˆ