-- RTTypesRemotePrivateImpl.Mesa
-- last modified on May 25, 1983 10:06 am by Paul Rovner

DIRECTORY
AMBridge USING[WordSequence, WordSequenceRecord, RemotePD, RemoteGlobalFrameHandle,
RemoteFrameHandle, RemoteRef, RemoteSED, RemotePointer,
TVForRemoteFrame, nilRemotePD, nilRemoteGlobalFrameHandle,
nilRemoteFrameHandle, GetWorld],
AMProcessBasic USING[ReturnLink],
AMTypes USING[Error, TypedVariable, TVType],
BcdDefs USING[MTIndex, BCD, FTSelf, SGIndex, SGNull, FTIndex, NameRecord, VersionStamp],
BcdOps USING[BcdBase, MTHandle, ProcessModules, NameString, FTHandle,
ProcessFiles],
BrandXSymbolDefs USING
[rootBodyIndex, SymbolTableBase, SymbolIdIndex, SymbolIndex,
BodyIndex],
BrandYSymbolDefs USING
[rootBodyIndex, SymbolTableBase, SymbolIdIndex, SymbolIndex,
BodyIndex],
ConvertUnsafe USING[ToRope],
Environment USING[wordsPerPage],
LongString USING[AppendChar, AppendOctal, SubStringDescriptor, AppendSubString],
PilotLoadStateOps USING[InputLoadState, ReleaseLoadState, GetModule, AcquireBcd],
PilotLoadStateFormat USING[LoadState, LoadStateObject, ModuleInfo],
PilotLoadStatePrivate USING[InstallLoadState],
PrincOps USING[BytePC, ControlLink, CSegPrefix, EntryVectorItem, EPRange, Frame,
FrameCodeBase, FrameHandle, GFTIndex, GlobalFrame, GlobalFrameHandle,
localbase, NullLink, ProcDesc, SignalDesc, UnboundLink, NullGlobalFrame],
PrincOpsRuntime USING[GFT, GFTItem, GetFrame],
Rope USING[ROPE, Concat],
RTBasic USING[Type, nullType],
RTCommon USING[Field, StoreFieldLong],
RTQuanta USING[QuantumIndex],
RTRefCounts USING[AGCState],
RTSD USING[sRTState, sMapStiStd],
RTSymbolDefs USING[SymbolTableBase, SymbolTableHandle, nullHandle, CallableBodyIndex,
BodyIndex, rootBodyIndex, SymbolIdIndex, SymbolRecordIndex,
SymbolIndex, nullBodyIndex],
RTSymbolOps USING[AcquireType, EnumerateRecordIseis, AcquireRope, NullISEI],
RTSymbols USING[ReleaseSTB, AcquireSTB],
RTSymbolsPrivate USING[AcquireSTHFromSTX, GetSTHForModule],
RTTypesBasicPrivate USING[TypeDesc, UniqueTypeFinger, STDesc, RMapTiTd,
PTypeDesc, FindSTI, PSTDesc, RMapStiStd, SymbolTableIndex,
MapStiStd],
RTTypesPrivate USING[TypedVariableRec, GetCBTI, ConvertCbti],
RTTypesRemotePrivate USING[RemoteErrorType, EVRange],
RTZones USING[ZoneFinger, SubZone, SubZoneIndex, TMapQZf, MapPtrQ, NodeHeader,
sizeNd, SubZoneRec, RMapQZf, RMapSziSz],
Runtime USING[ValidateFrame],
SDDefs USING[SD, sSignal, sGFTLength],
SafeStorage USING[NewZone],
Strings USING[SubStringDescriptor, AppendSubString],
Table USING[Base],
UnsafeStorage USING[NewUObject, GetSystemUZone],
WorldVM USING[Address, CopyRead, CopyWrite, Long, LongRead, LongWrite,
Read, ShortAddress, World, Write, Loadstate, Lock, Unlock,
CurrentIncarnation];

RTTypesRemotePrivateImpl: MONITOR -- protects the cache of remote BCDs
IMPORTS AMBridge, AMProcessBasic, AMTypes, BcdOps, ConvertUnsafe, LongString,
PilotLoadStateOps, PilotLoadStatePrivate, PrincOpsRuntime, Rope, RTCommon,
RTSymbolOps, RTSymbols, RTSymbolsPrivate, RTTypesBasicPrivate, RTTypesPrivate,
RTZones, Runtime, SafeStorage, Strings, UnsafeStorage, WorldVM
EXPORTS RTTypesRemotePrivate

= BEGIN OPEN AMBridge, AMTypes, bx: BrandXSymbolDefs, by: BrandYSymbolDefs, RTBasic,
RTSymbolDefs, RTSymbolOps, RTSymbols, RTTypesPrivate, RTTypesRemotePrivate,
WorldVM;

z: ZONE = SafeStorage.NewZone[prefixed];

-- TYPES
RemoteBCDCache: TYPE = LIST OF BCDCacheRec;
BCDCacheRec: TYPE = RECORD[world: World ← ,
remoteBCD: Address ← ,
localBCD: BcdOps.BcdBase ← ,
useCount: INT ← ];
-- VARIABLES
remoteBCDCache: RemoteBCDCache ← NIL;
remoteBCDCacheLength: NAT ← 0;
maxRemoteBCDCacheLength: NAT ← 1;

-- CONSTANTS
SignallerFrameMessageOffset: NAT = 9;
SignallerFrameSignalOffset: NAT = 7;

-- S I G N A L S

RemoteError: PUBLIC ERROR[type: RemoteErrorType,
message: LONG POINTER TO TEXTNIL] = CODE;

-- P R O C E D U R E S

--XXX
-- raises notImplemented
ValidateRemoteRef: PUBLIC PROC[ref: RemoteRef] =
{IF FALSE THEN ERROR AMTypes.Error[reason: notImplemented, msg: "ValidateRemoteRef"];
};

SameCode: PUBLIC PROC [f1, f2: RemoteGlobalFrameHandle] RETURNS [BOOL] =
{ fcb1, fcb2: PrincOps.FrameCodeBase;
fcb1 ← GetRemoteGFHeader[f1].code;
fcb2 ← GetRemoteGFHeader[f2].code;
fcb1.out ← fcb2.out ← FALSE;
RETURN[fcb1 = fcb2]};

EnumerateRemoteGlobalFrames: PUBLIC PROC[world: World,
proc: PROC[RemoteGlobalFrameHandle]
RETURNS[BOOLEAN]]
RETURNS[RemoteGlobalFrameHandle] =
{ gftLength: CARDINAL;

{ ENABLE UNWIND => Unlock[world];
Lock[world];
gftLength ← Read[world: world,
addr: Long[world: world,
addr: LOOPHOLE[SDDefs.SD + SDDefs.sGFTLength,
ShortAddress]]];
FOR i: CARDINAL IN [1..gftLength) DO
item: PrincOpsRuntime.GFTItem;
frame: PrincOps.GlobalFrameHandle;
CopyRead[world: world,
from: Long[world: world,
addr: LOOPHOLE[PrincOpsRuntime.GFT
+ i * SIZE[PrincOpsRuntime.GFTItem],
ShortAddress]],
nwords: SIZE[PrincOpsRuntime.GFTItem],
to: @item];
frame ← PrincOpsRuntime.GetFrame[item];
IF frame # PrincOps.NullGlobalFrame AND item.epbias = 0 THEN
{IF proc[[world: world,
worldIncarnation: CurrentIncarnation[world],
gfh: LOOPHOLE[frame, ShortAddress]]]
THEN {Unlock[world]; RETURN[[world: world,
worldIncarnation: CurrentIncarnation[world],
gfh: LOOPHOLE[frame, ShortAddress]]]}};
ENDLOOP;
Unlock[world];
RETURN[nilRemoteGlobalFrameHandle]}};

-- MOVE NOTE PROBLEM!
AcquireSTBFromRemoteGFH: PUBLIC PROC[gfh: RemoteGlobalFrameHandle]
RETURNS[SymbolTableBase] =
{ mappedBCD: BcdOps.BcdBase;
module: PilotLoadStateFormat.ModuleInfo; -- a loadstate.gft entry
std: RTTypesBasicPrivate.STDesc;
sth: SymbolTableHandle;
mth: BcdOps.MTHandle;
ftb: Table.Base;
sti: RTTypesBasicPrivate.SymbolTableIndex;

FindModule: PROC [mth: BcdOps.MTHandle, mti: BcdDefs.MTIndex] RETURNS [BOOLEAN] =
{RETURN[module.gfi IN [mth.gfi .. mth.gfi + mth.ngfi)]};

[mappedBCD, module] ← AcquireRemoteBCDAndModule[gfh];

-- here with the copied remote BCD. Now poke around in the remote bcd to find
-- the version stamp, then get the symboltable
ftb ← LOOPHOLE[LOOPHOLE[mappedBCD, LONG POINTER] + mappedBCD.ftOffset, Table.Base];

[mth, ] ← BcdOps.ProcessModules[LOOPHOLE[mappedBCD], FindModule
! UNWIND => ReleaseRemoteBCD[mappedBCD]];
IF mth = NIL THEN ERROR;

std ← [symbolsStamp: IF mth.file = BcdDefs.FTSelf
THEN mappedBCD.version
ELSE ftb[mth.file].version];
ReleaseRemoteBCD[mappedBCD];

sti ← RTTypesBasicPrivate.FindSTI[std];
sth ← RTSymbolsPrivate.AcquireSTHFromSTX[sti].sth;
IF sth = nullHandle
THEN {moduleName: Rope.ROPE = RemoteGFHToName[gfh: gfh, moduleNameOnly: TRUE];
sth ← RTSymbolsPrivate.GetSTHForModule[stamp: std.symbolsStamp,
moduleName: moduleName,
fileName: Rope.Concat[moduleName,
".bcd"]];
IF sth # nullHandle
THEN RTTypesBasicPrivate.MapStiStd[sti].sth ← sth;
};
IF sth = nullHandle
THEN ERROR AMTypes.Error[reason: noSymbols,
msg: RemoteGFHToName[gfh]]
ELSE RETURN[AcquireSTB[sth]];
};

-- raises Error
AcquireRemoteBCDAndModule: PUBLIC PROC[gfh: RemoteGlobalFrameHandle]
RETURNS[BcdOps.BcdBase, PilotLoadStateFormat.ModuleInfo] =
{ bcd: BcdOps.BcdBase; -- remote bcd
module: PilotLoadStateFormat.ModuleInfo; -- a loadstate.gft entry
world: World = gfh.world;
mappedBCD: BcdOps.BcdBase;

FindOriginal: PROCEDURE [f: RemoteGlobalFrameHandle] RETURNS [BOOLEAN] =
{RETURN[(f.gfh # gfh.gfh)
AND (SameCode[gfh, f])
AND (~GetRemoteGFHeader[f].copied)]};

IF gfh.gfh = 0 THEN ERROR AMTypes.Error[reason: noSymbols];

{ ENABLE UNWIND => Unlock[world];
loadStateHeld: BOOLEANFALSE;
oldState: PilotLoadStateFormat.LoadState;
newState: REF PilotLoadStateFormat.LoadStateObject;

Lock[world];

{ ENABLE ANY => IF loadStateHeld
THEN {PilotLoadStateOps.ReleaseLoadState[];
loadStateHeld ← FALSE};

IF GetRemoteGFHeader[gfh].copied
THEN gfh ← EnumerateRemoteGlobalFrames[world, FindOriginal];

newState ← Loadstate[gfh.world];
loadStateHeld ← TRUE;
[] ← PilotLoadStateOps.InputLoadState[];
oldState ← PilotLoadStatePrivate.InstallLoadState[LOOPHOLE[newState]]; -- no error raised

-- now find the bcd and module of interest

module ← PilotLoadStateOps.GetModule[GetRemoteGFHeader[gfh].gfi];

IF NOT loadStateHeld
THEN {loadStateHeld ← TRUE;
[] ← PilotLoadStateOps.InputLoadState[];
[] ← PilotLoadStatePrivate.InstallLoadState[LOOPHOLE[newState]];-- no error raised--};

bcd ← PilotLoadStateOps.AcquireBcd -- NOTE assume that it doesn't need to be released
[config: module.config];

IF NOT loadStateHeld
THEN {loadStateHeld ← TRUE;
[] ← PilotLoadStateOps.InputLoadState[];
[] ← PilotLoadStatePrivate.InstallLoadState[LOOPHOLE[newState]];-- no error raised--};

[] ← PilotLoadStatePrivate.InstallLoadState[oldState];
PilotLoadStateOps.ReleaseLoadState[];
loadStateHeld ← FALSE}; -- end ENABLE ANY

mappedBCD ← AcquireRemoteBCD[world: gfh.world, bcd: bcd];
Unlock[world];
}; -- end ENABLE UNWIND

RETURN[mappedBCD, module];
}; -- end AcquireRemoteBCDAndModule

ReleaseRemoteBCD: PUBLIC ENTRY PROC[bcd: BcdOps.BcdBase] =
{ENABLE UNWIND => NULL;
FOR l: RemoteBCDCache ← remoteBCDCache, l.rest UNTIL l = NIL
DO IF l.first.localBCD = bcd
THEN {l.first.useCount ← l.first.useCount - 1;
IF remoteBCDCacheLength > maxRemoteBCDCacheLength
THEN {prev: RemoteBCDCache ← NIL;
FOR s: RemoteBCDCache ← remoteBCDCache, s.rest UNTIL s = NIL
DO IF s.first.useCount = 0
THEN {nBCD: BcdOps.BcdBase ← s.first.localBCD;
UnsafeStorage.GetSystemUZone[].FREE[@nBCD];
IF prev = NIL
THEN remoteBCDCache ← s.rest
ELSE prev.rest ← s.rest;
EXIT};
prev ← s;
ENDLOOP};
RETURN};
ENDLOOP;
ERROR;
};

FindCachedRemoteBCD: ENTRY PROC[world: World, remoteBCD: Address]
RETURNS[localBCD: BcdOps.BcdBase ← NIL] =
{ENABLE UNWIND => NULL;
prev: RemoteBCDCache ← NIL;
FOR l: RemoteBCDCache ← remoteBCDCache, l.rest UNTIL l = NIL
DO IF l.first.world = world AND l.first.remoteBCD = remoteBCD
THEN {l.first.useCount ← l.first.useCount + 1;
IF prev = NIL THEN remoteBCDCache ← l.rest ELSE prev.rest ← l.rest; -- unhook it
l.rest ← remoteBCDCache; -- stick it at the beginning (most recent)
remoteBCDCache ← l;
RETURN[l.first.localBCD];
};
prev ← l;
ENDLOOP;
};

EnterRemoteBCDInCache: ENTRY PROC[world: World,
remoteBCD: Address,
localBCD: BcdOps.BcdBase] =
{ENABLE UNWIND => NULL;
FOR l: RemoteBCDCache ← remoteBCDCache, l.rest UNTIL l = NIL
DO IF l.rest = NIL
THEN {l.rest ← CONS[[world: world,
remoteBCD: remoteBCD,
localBCD: localBCD,
useCount: 1],
NIL];
RETURN;
};
ENDLOOP;
remoteBCDCache ← CONS[[world: world,
remoteBCD: remoteBCD,
localBCD: localBCD,
useCount: 1],
NIL];
};

-- assumes world is locked
AcquireRemoteBCD: PUBLIC PROC[world: World, bcd: BcdOps.BcdBase--remote--]
RETURNS[mappedBCD: BcdOps.BcdBase ← NIL--local--] =
{ pages: NAT;
mappedBCD ← FindCachedRemoteBCD[world, LOOPHOLE[bcd, Address]];
IF mappedBCD # NIL THEN RETURN[mappedBCD];
mappedBCD ← UnsafeStorage.NewUObject
[size: Environment.wordsPerPage,
zone: UnsafeStorage.GetSystemUZone[]];
CopyRead[world: world,
from: LOOPHOLE[bcd, Address],
nwords: SIZE[BcdDefs.BCD],
to: LOOPHOLE[mappedBCD, LONG POINTER]
! UNWIND => UnsafeStorage.GetSystemUZone[].FREE[@mappedBCD]];

IF mappedBCD.extended
THEN pages ← mappedBCD.nPages - mappedBCD.rtPages.pages
ELSE pages ← mappedBCD.nPages;

UnsafeStorage.GetSystemUZone[].FREE[@mappedBCD];
mappedBCD ← UnsafeStorage.NewUObject[size: pages*Environment.wordsPerPage,
zone: UnsafeStorage.GetSystemUZone[]];
CopyRead[world: world,
from: LOOPHOLE[bcd, Address],
nwords: pages*Environment.wordsPerPage,
to: LOOPHOLE[mappedBCD, LONG POINTER]
! UNWIND => UnsafeStorage.GetSystemUZone[].FREE[@mappedBCD]];
EnterRemoteBCDInCache[world: world,
remoteBCD: LOOPHOLE[bcd, Address],
localBCD: mappedBCD];
};

RemoteGFHToName: PUBLIC PROC[gfh: RemoteGlobalFrameHandle,
moduleNameOnly: BOOLFALSE]
RETURNS[ans: Rope.ROPENIL] =
{ s: STRING ← [80];
bcd: BcdOps.BcdBase;
module: PilotLoadStateFormat.ModuleInfo;
ssb: BcdOps.NameString;

AppendBracketed: PROC [s: STRING, value: CARDINAL] = INLINE
{IF moduleNameOnly THEN RETURN;
LongString.AppendChar[s, '[];
LongString.AppendOctal[s, value];
LongString.AppendChar[s, ']]};

FindModuleString: PROC[mth: BcdOps.MTHandle, mti: BcdDefs.MTIndex]
RETURNS [stop: BOOLEAN] =
{ ssd: LongString.SubStringDescriptor;
IF module.gfi IN [mth.gfi..mth.gfi + mth.ngfi)
THEN {ssd ← [base: @ssb.string, offset: mth.name, length: ssb.size[mth.name]];
s.length ← 0;
LongString.AppendSubString[s, @ssd];
IF GetRemoteGFHeader[gfh].copied
THEN AppendBracketed[s, GetRemoteGFHeader[gfh].gfi];
RETURN[TRUE]}
ELSE RETURN[FALSE]};

[bcd, module] ← AcquireRemoteBCDAndModule[gfh];
ssb ← LOOPHOLE[bcd + bcd.ssOffset, BcdOps.NameString];

[] ← BcdOps.ProcessModules[bcd, FindModuleString
! ANY => {s.length ← 0;
AppendBracketed[s, GetRemoteGFHeader[gfh].gfi];
CONTINUE}];
ReleaseRemoteBCD[bcd];
RETURN[ConvertUnsafe.ToRope[LONG[s]]]
};

RemoteTypeToLocal: PUBLIC PROC[world: World, remoteType: CARDINAL]
RETURNS[type: Type] =
{stb: SymbolTableBase;
td: RTTypesBasicPrivate.TypeDesc; -- copied from the remote world. NO REFS.
sth: SymbolTableHandle;
seIndex: SymbolIndex;
-- seIndex must be consistent with sth:
-- either symbols from the UTF or from the Typs's symbol access info
CopyRead[world: world,
from: LongRead[world: world,
addr: LOOPHOLE[WorldRoot[world].GCStateBasic.mapTiTd
+ SIZE[RTTypesBasicPrivate.RMapTiTd[0]]
+ LOOPHOLE[remoteType, CARDINAL]
*SIZE[RTTypesBasicPrivate.PTypeDesc],
Address]],
nwords: SIZE[RTTypesBasicPrivate.TypeDesc],
to: @td];
-- first try for the original defining module
seIndex ← td.utf.seIndex; -- utf: (umid: original defining module, seIndex: sei therein)
sth ← RTSymbolsPrivate.AcquireSTHFromSTX
[RTTypesBasicPrivate.FindSTI[[symbolsStamp: td.utf.umid]]].sth;

IF sth = nullHandle -- not easy. Try harder using symbol access info for the remote type.
THEN {remoteBCD: BcdOps.BcdBase;
remoteSGI: BcdDefs.SGIndex;
remoteSymbolsStamp: BcdDefs.VersionStamp;
[remoteBCD, remoteSGI, remoteSymbolsStamp]
← WorldMapStiStdEntry[world: world, remoteSTI: td.symbolAccess.sti];
IF remoteBCD # NIL
THEN {moduleName: Rope.ROPE ← NIL;
mappedBCD: BcdOps.BcdBase ← AcquireRemoteBCD[world: world,
bcd: remoteBCD];
{ ENABLE UNWIND => ReleaseRemoteBCD[mappedBCD];
ssb: BcdOps.NameString
= LOOPHOLE[mappedBCD + mappedBCD.ssOffset, BcdOps.NameString];

IF remoteSGI = BcdDefs.SGNull
THEN
-- go again for the defining module, this time with its name
-- (search the BCD's file table)
{ findSymbolFTI: PROC[ffth: BcdOps.FTHandle,
ffti: BcdDefs.FTIndex]
RETURNS[stop: BOOLEAN] =
{ IF ffth.version # remoteSymbolsStamp THEN RETURN[FALSE];
moduleName ← GetModuleName[ssb, ffth.name];
RETURN[TRUE]};
remoteSymbolsStamp ← td.utf.umid;
[] ← BcdOps.ProcessFiles[mappedBCD, findSymbolFTI];
IF moduleName = NIL THEN ERROR;
}
ELSE -- go for the module specified by the SGI
{sgb: Table.Base
= LOOPHOLE[mappedBCD + mappedBCD.sgOffset, Table.Base];
ftb: Table.Base
= LOOPHOLE[mappedBCD + mappedBCD.ftOffset, Table.Base];
fti: BcdDefs.FTIndex ← sgb[remoteSGI].file;
seIndex ← td.symbolAccess.sei;
IF fti = BcdDefs.FTSelf
THEN moduleName ← GetModuleName[ssb, mappedBCD.source]
-- NOTE module name vs file name
ELSE moduleName ← GetModuleName[ssb, ftb[fti].name]};
}; -- end ENABLE UNWIND

ReleaseRemoteBCD[mappedBCD];
sth ← RTSymbolsPrivate.GetSTHForModule
[stamp: remoteSymbolsStamp,
moduleName: moduleName,
fileName: Rope.Concat[moduleName, ".bcd"]];
}; -- end remoteBCD # NIL
}; -- end sth = nullHandle

IF sth = nullHandle THEN ERROR AMTypes.Error[reason: noSymbols];
stb ← AcquireSTB[sth];
type ← AcquireType[stb: stb, seIndex: seIndex ! UNWIND => ReleaseSTB[stb]];
ReleaseSTB[stb];
}; -- end RemoteTypeToLocal

GetModuleName: PROC[ssb: BcdOps.NameString, n: BcdDefs.NameRecord] RETURNS[Rope.ROPE] =
{nameString: STRING = [100];
ssd: Strings.SubStringDescriptor ← [base: @ssb.string, offset: n, length: MIN[ssb.size[n], 100]];
nameString.length ← 0;
Strings.AppendSubString[nameString, @ssd];
FOR i: CARDINAL IN [0..nameString.length) DO
IF nameString[i] = '. THEN {nameString.length ← i; EXIT};
ENDLOOP;
RETURN[ConvertUnsafe.ToRope[LONG[nameString]]]};

-- raises RemoteError
ValidateRemoteFrame: PUBLIC PROC[remoteFH: RemoteFrameHandle] =
{frame: rep PrincOps.ControlLink = LOOPHOLE[remoteFH.fh, rep PrincOps.ControlLink];
IF frame.proc
OR frame.indirect
OR ~ValidRemoteGlobalFrame[[world: remoteFH.world,
worldIncarnation: CurrentIncarnation[remoteFH.world],
gfh: LOOPHOLE[GetRemoteFrameHeader[remoteFH].accesslink,
WorldVM.ShortAddress]]]
THEN ERROR RemoteError[invalidFrame]};

ValidRemoteGlobalFrame: PROC[gfh: RemoteGlobalFrameHandle]
RETURNS[ans: BOOLEANFALSE] =
{h: rep PrincOps.ControlLink = LOOPHOLE[gfh.gfh, rep PrincOps.ControlLink];
ans ← NOT h.proc AND NOT h.indirect AND InRemoteGFT[gfh ! ANY => CONTINUE]};

InRemoteGFT: PROC[gfh: RemoteGlobalFrameHandle] RETURNS[BOOLEAN] =
{gftLength: CARDINAL;
world: World = gfh.world;

{ ENABLE UNWIND => Unlock[world];
Lock[world];

gftLength ← Read[world: world,
addr: Long[world: world,
addr: LOOPHOLE[SDDefs.SD + SDDefs.sGFTLength,
ShortAddress]]];
FOR k: CARDINAL IN [1..gftLength) DO
IF GetRemoteGFHandle[world: world, gfi: k] = gfh
AND GetRemoteGFHeader[gfh].gfi = k
THEN {Unlock[world]; RETURN[TRUE]};
ENDLOOP;
Unlock[world];
RETURN[FALSE];
}};

-- NOTE copies the AGCState (but not MapPiRce and MapOiOe)
WorldRoot: PROC[world: World] RETURNS[ans: REF RTRefCounts.AGCState] =
{ans ← z.NEW[RTRefCounts.AGCState];
CopyRead[world: world,
from: LOOPHOLE[LongRead[world: world,
addr: Long[world: world,
addr: LOOPHOLE[SDDefs.SD + RTSD.sRTState,
ShortAddress]]],
Address],
nwords: SIZE[RTRefCounts.AGCState],
to: LOOPHOLE[ans, LONG POINTER]
];
};

WorldMapStiStdEntry: PROC[world: World, remoteSTI: RTTypesBasicPrivate.SymbolTableIndex]
RETURNS[BcdOps.BcdBase, BcdDefs.SGIndex, BcdDefs.VersionStamp] =
{ans: RTTypesBasicPrivate.STDesc;
CopyRead[ world: world,
from: LOOPHOLE
[LongRead
[world: world,
addr: LOOPHOLE[LongRead[world: world,
addr: Long[world: world,
addr: LOOPHOLE
[SDDefs.SD
+ RTSD.sMapStiStd,
ShortAddress]]],
Address] -- MapStiStd
+ SIZE[RTTypesBasicPrivate.RMapStiStd[0]]
+ SIZE[RTTypesBasicPrivate.PSTDesc] * remoteSTI],
Address],
nwords: SIZE[RTTypesBasicPrivate.STDesc],
to: @ans
];
RETURN[ans.bcd, ans.sgi, ans.symbolsStamp]
};

GetRemotePc: PUBLIC PROC[gf: RemoteGlobalFrameHandle, i: EVRange]
RETURNS [PrincOps.BytePC] =
{codeBase: RemotePointer -- LONG POINTER TO PrincOps.CSegPrefix
= GetRemoteEntryTableBase[gf];
wpc: CARDINAL ← Read[world: gf.world,
addr: LOOPHOLE[codeBase.ptr, Address]
+ SIZE[PrincOps.CSegPrefix]
+ i*SIZE[PrincOps.EntryVectorItem]];
RETURN[LOOPHOLE[wpc*2, PrincOps.BytePC]]};

GetRemoteEntryTableBase: PROC [gfh: RemoteGlobalFrameHandle]
RETURNS [RemotePointer] =
{c: PrincOps.FrameCodeBase ← GetRemoteGFHeader[gfh].code;
c.out ← FALSE;
RETURN[[world: gfh.world,
worldIncarnation: CurrentIncarnation[gfh.world],
ptr: LOOPHOLE[c, Address]]];
};

-- raises typeFault
UnwindRemoteIndirectProcDesc: PUBLIC PROC[pd: RemotePD] RETURNS[RemotePD] =
{icl: PrincOps.ControlLink ← LOOPHOLE[pd.pd, PrincOps.ControlLink];
world: World = pd.world;

IF icl = PrincOps.NullLink OR icl = PrincOps.UnboundLink
THEN RETURN[nilRemotePD];

{ ENABLE UNWIND => Unlock[world];
Lock[world];

UNTIL icl.proc DO
IF icl.indirect
THEN icl ← LOOPHOLE[Read[world: world,
addr: Long[world: world,
addr: LOOPHOLE[icl.link, ShortAddress]]],
PrincOps.ControlLink]
ELSE ERROR Error[reason: typeFault, type: nullType]
ENDLOOP;
Unlock[world];
RETURN[[world: world, worldIncarnation: CurrentIncarnation[world], pd: icl]]}};

-- break up and MOVE
AcquireCBTHandleFromRemotePD: PUBLIC PROC[pd: RemotePD]
RETURNS[stb: SymbolTableBase, cbti: CallableBodyIndex] =
{ item: PrincOpsRuntime.GFTItem;
world: World = pd.world;

{ ENABLE UNWIND => Unlock[world];
Lock[world];

pd ← UnwindRemoteIndirectProcDesc[pd];
CopyRead[world: world,
from: Long[world: world,
addr: LOOPHOLE[PrincOpsRuntime.GFT
+ (LOOPHOLE[pd.pd, PrincOps.ProcDesc].gfi
* SIZE[PrincOpsRuntime.GFTItem]),
ShortAddress]],
nwords: SIZE[PrincOpsRuntime.GFTItem],
to: @item
];
stb ← AcquireSTBFromRemoteGFH
[GetRemoteGFHandle[world: world,
gfi: LOOPHOLE[pd.pd, PrincOps.ProcDesc].gfi]];
cbti ← RTTypesPrivate.GetCBTI
[stb,
item.epbias * PrincOps.EPRange
+ LOOPHOLE[pd.pd, PrincOps.ProcDesc].ep];
Unlock[world]}};

GetRemoteGFHandle: PUBLIC PROC[world: World, gfi: PrincOps.GFTIndex]
RETURNS[RemoteGlobalFrameHandle] =
{item: PrincOpsRuntime.GFTItem;

{ ENABLE UNWIND => Unlock[world];
Lock[world];

CopyRead[world: world,
from: Long[world: world,
addr: LOOPHOLE[PrincOpsRuntime.GFT
+ gfi * SIZE[PrincOpsRuntime.GFTItem],
ShortAddress]],
nwords: SIZE[PrincOpsRuntime.GFTItem],
to: @item
];
Unlock[world];
RETURN[[world: world,
worldIncarnation: CurrentIncarnation[world],
gfh: LOOPHOLE[PrincOpsRuntime.GetFrame[item], ShortAddress]]]};
};

GetRemoteGFHeader: PUBLIC PROC[gfh: RemoteGlobalFrameHandle]
RETURNS[ans: REF PrincOps.GlobalFrame] =
{world: World = gfh.world;

ans ← z.NEW[PrincOps.GlobalFrame];
{ ENABLE UNWIND => Unlock[world];
Lock[world];

CopyRead[world: world,
from: Long[world: world,
addr: LOOPHOLE[gfh.gfh, ShortAddress]],
nwords: SIZE[PrincOps.GlobalFrame],
to: LOOPHOLE[ans, LONG POINTER]];
Unlock[world];
}};

GetRemoteFrameHeader: PUBLIC PROC[fh: RemoteFrameHandle]
RETURNS[ans: REF PrincOps.Frame] =
{world: World = fh.world;
ans ← z.NEW[PrincOps.Frame];

{ ENABLE UNWIND => Unlock[world];
Lock[world];

CopyRead[world: world,
from: Long[world: world,
addr: LOOPHOLE[fh.fh, ShortAddress]],
nwords: SIZE[PrincOps.Frame],
to: LOOPHOLE[ans, LONG POINTER]];
Unlock[world];
}};

GetRemoteReferentType: PUBLIC PROC[remoteRef: RemoteRef]
RETURNS[type: Type--valid locally--] =
{ mz: RTZones.ZoneFinger;
world: World = remoteRef.world;

IF remoteRef.ref = 0 THEN RETURN[nullType];

{ ENABLE UNWIND => Unlock[world];
Lock[world];

mz ← RemoteMapRefZf[remoteRef];
WITH mz: mz SELECT FROM
prefixed => type ← GetRemotePrefixedType[remoteRef];
sub => type ← GetRemoteSzType[world: world, szi: mz.szi];
ENDCASE => ERROR;
Unlock[world]}};

RemoteMapRefZf: PROC[remoteRef: RemoteRef]
RETURNS[zf: RTZones.ZoneFinger] =
{qi: RTQuanta.QuantumIndex = RTZones.MapPtrQ[LOOPHOLE[remoteRef.ref, LONG POINTER]];
remoteMapQZf: RTZones.TMapQZf = WorldRoot[remoteRef.world].GCStateBasic.mapQZf;
CopyRead[world: remoteRef.world,
from: LOOPHOLE[remoteMapQZf
+ SIZE[RTZones.RMapQZf[0]]
+ qi*SIZE[RTZones.ZoneFinger],
Address],
nwords: SIZE[RTZones.ZoneFinger],
to: @zf];
};

GetRemotePrefixedType: PROC[remoteRef: RemoteRef]
RETURNS[Type--valid locally--] =
{remoteType: CARDINAL;
NHdr: inuse RTZones.NodeHeader;
CopyRead[world: remoteRef.world,
from: remoteRef.ref - RTZones.sizeNd,
nwords: SIZE[inuse RTZones.NodeHeader],
to: @NHdr];
remoteType ← NHdr.type;
RETURN[RemoteTypeToLocal[world: remoteRef.world, remoteType: remoteType]];
};

GetRemoteSzType: PROC[world: World, szi: RTZones.SubZoneIndex]
RETURNS[Type--valid locally--] =
{remoteType: CARDINAL;
szrp: Address; -- SubZone
szRec: RTZones.SubZoneRec;
szrp ← LongRead
[world: world,
addr: LOOPHOLE[WorldRoot[world].GCStateBasic.mapSziSz
+ SIZE[RTZones.RMapSziSz[0]]
+ szi*SIZE[RTZones.SubZone],
Address]];
CopyRead[world: world,
from: szrp,
nwords: SIZE[RTZones.SubZoneRec],
to: @szRec];
remoteType ← szRec.type;
RETURN[RemoteTypeToLocal[world: world, remoteType: remoteType]];
};

-- MOVE
GetRemoteProcedureType: PUBLIC PROC[remotePD: RemotePD]
RETURNS[type: Type--valid locally--] =
{ stb: SymbolTableBase;
cbti: CallableBodyIndex;
[stb, cbti] ← AcquireCBTHandleFromRemotePD[remotePD];
type ← AcquireType
[stb,
WITH stb SELECT FROM
t: SymbolTableBase.x => [x[t.e.bb[NARROW[cbti, CallableBodyIndex.x].e].ioType]],
t: SymbolTableBase.y => [y[t.e.bb[NARROW[cbti, CallableBodyIndex.y].e].ioType]],
ENDCASE => ERROR,
! UNWIND => ReleaseSTB[stb]];
ReleaseSTB[stb]};

-- break up and MOVE
GetRemoteSignalType: PUBLIC PROC[remoteSED: RemoteSED]
RETURNS[type: Type--valid locally--] =
{ gfh: RemoteGlobalFrameHandle ← nilRemoteGlobalFrameHandle;
item: PrincOpsRuntime.GFTItem;
stb: SymbolTableBase;
world: World = remoteSED.world;

proc: PROC[stb: SymbolTableBase, isei: SymbolIdIndex]
RETURNS[stop: BOOLEAN] =
{WITH stb SELECT FROM
t: SymbolTableBase.x => RETURN[procX[t.e, NARROW[isei, SymbolIdIndex.x].e]];
t: SymbolTableBase.y => RETURN[procY[t.e, NARROW[isei, SymbolIdIndex.y].e]];
ENDCASE => ERROR};
procX: PROC[stb: bx.SymbolTableBase, isei: bx.SymbolIdIndex]
RETURNS[stop: BOOLEAN] =
{ tsei: bx.SymbolIndex;
IF stb.seb[isei].constant
AND stb.seb[tsei ← stb.UnderType[stb.seb[isei].idType]].typeTag = transfer
AND (SELECT stb.XferMode[tsei] FROM
error, signal => TRUE,
ENDCASE => FALSE)
AND CARDINAL[item.epbias * PrincOps.EPRange
+ LOOPHOLE[remoteSED.sed, PrincOps.SignalDesc].ep] =
STInfoToEPN[LOOPHOLE[stb.seb[isei].idValue, PrincOps.SignalDesc]]
THEN {type ← AcquireType[[x[stb]], [x[stb.seb[isei].idType]]];
RETURN[TRUE]}
ELSE RETURN[FALSE]};
procY: PROC[stb: by.SymbolTableBase, isei: by.SymbolIdIndex]
RETURNS[stop: BOOLEAN] =
{ tsei: by.SymbolIndex;
IF stb.seb[isei].constant
AND stb.seb[tsei ← stb.UnderType[stb.seb[isei].idType]].typeTag = transfer
AND (SELECT stb.XferMode[tsei] FROM
error, signal => TRUE,
ENDCASE => FALSE)
AND CARDINAL[item.epbias * PrincOps.EPRange
+ LOOPHOLE[remoteSED.sed, PrincOps.SignalDesc].ep] =
STInfoToEPN[LOOPHOLE[stb.seb[isei].idValue, PrincOps.SignalDesc]]
THEN {type ← AcquireType[[y[stb]], [y[stb.seb[isei].idType]]];
RETURN[TRUE]}
ELSE RETURN[FALSE]};

-- START GetRemoteSignalType HERE

IF LOOPHOLE[remoteSED.sed, CARDINAL] = 177777B -- ERROR
OR LOOPHOLE[remoteSED.sed, CARDINAL] = LOOPHOLE[UNWIND, CARDINAL]
OR LOOPHOLE[remoteSED.sed, CARDINAL] = LOOPHOLE[ABORTED, CARDINAL]
THEN RETURN[CODE[ERROR]];

{ ENABLE UNWIND => Unlock[world];
Lock[world];

gfh ← GetRemoteGFHandle[world: world,
gfi: LOOPHOLE[remoteSED.sed,
PrincOps.SignalDesc].gfi];
stb ← AcquireSTBFromRemoteGFH[gfh];
CopyRead[world: world,
from: Long[world: world,
addr: LOOPHOLE[PrincOpsRuntime.GFT
+ LOOPHOLE[remoteSED.sed,
PrincOps.SignalDesc].gfi
* SIZE[PrincOpsRuntime.GFTItem],
ShortAddress]],
nwords: SIZE[PrincOpsRuntime.GFTItem],
to: @item
];
type ← nullType;
[] ← EnumerateRecordIseis
[stb,
WITH stb SELECT FROM
t: SymbolTableBase.x => [x[t.e.bb[bx.rootBodyIndex].type]],
t: SymbolTableBase.y => [y[t.e.bb[by.rootBodyIndex].type]],
ENDCASE => ERROR,
proc
! UNWIND => ReleaseSTB[stb]];
ReleaseSTB[stb];
Unlock[world]}};

-- break up and MOVE
IsRemoteCatchFrame: PUBLIC PROC[remoteFrameHandle: RemoteFrameHandle,
bti: BodyIndex]
RETURNS [isCatchFrame: BOOLEANTRUE,
revBti: BodyIndex] =
{world: World = remoteFrameHandle.world;

{ ENABLE UNWIND => Unlock[world];
Lock[world];

revBti ← bti;
ValidateRemoteFrame[remoteFrameHandle ! ANY => GOTO notCatch];
{ -- return FALSE if input invalid
nextFrame: RemoteFrameHandle
← [world: remoteFrameHandle.world,
worldIncarnation: CurrentIncarnation[remoteFrameHandle.world],
fh: LOOPHOLE[AMProcessBasic.ReturnLink
[world,
LOOPHOLE[remoteFrameHandle.fh, PrincOps.FrameHandle]],
ShortAddress]];
nextFHdr: REF PrincOps.Frame;

ValidateRemoteFrame[nextFrame ! ANY => GOTO notCatch];
-- return FALSE if no valid calling frame
nextFHdr ← GetRemoteFrameHeader[nextFrame];
IF nextFHdr.accesslink # RemoteSigGF[remoteFrameHandle.world]
THEN GOTO notCatch;

{ -- return FALSE if caller not signaller
sl: CARDINAL = LOOPHOLE[GetRemoteFrameHeader[remoteFrameHandle].staticlink];
L0Frame: RemoteFrameHandle
← [world: remoteFrameHandle.world,
worldIncarnation: CurrentIncarnation[remoteFrameHandle.world],
fh: 0];
IF sl = 0 THEN GOTO notCatch;
L0Frame ← [world: remoteFrameHandle.world,
worldIncarnation: CurrentIncarnation[remoteFrameHandle.world],
fh: LOOPHOLE[sl - PrincOps.localbase, ShortAddress]];
-- L0Frame is the frame that encloses the catch frame
ValidateRemoteFrame[L0Frame ! ANY => GOTO notCatch];
-- return FALSE if static frame not valid (??)
IF GetRemoteFrameHeader[remoteFrameHandle].accesslink
# GetRemoteFrameHeader[L0Frame].accesslink
THEN GOTO notCatch;
IF ~nextFHdr.mark THEN GOTO notCatch; -- calling frame not the signaller
{ -- detect situation where catch frame has no locals, thus no body table.
tr: REF TypedVariableRec = NARROW[TVForRemoteFrame[L0Frame],
REF TypedVariableRec];
WITH hd: tr.head SELECT FROM
remoteFH => IF bti = hd.bti THEN revBti ← nullBodyIndex;
ENDCASE => ERROR
};
Unlock[world];
}
};
EXITS
notCatch => {Unlock[world];
isCatchFrame ← FALSE}}};

RemoteSigGF: PROC[world: World] RETURNS[PrincOps.GlobalFrameHandle] =
{ item: PrincOpsRuntime.GFTItem;
pd: PrincOps.ProcDesc
= LOOPHOLE[Read[world: world,
addr: Long[world: world,
addr: LOOPHOLE[SDDefs.SD + SDDefs.sSignal,
ShortAddress]]],
PrincOps.ProcDesc];
CopyRead[world: world,
from: Long[world: world,
addr: LOOPHOLE[PrincOpsRuntime.GFT
+ pd.gfi * SIZE[PrincOpsRuntime.GFTItem],
ShortAddress]],
nwords: SIZE[PrincOpsRuntime.GFTItem],
to: @item
];
RETURN[PrincOpsRuntime.GetFrame[item]]};


-- MOVE
AcquireBTIFromRemoteFH: PUBLIC PROC[remoteFrameHandle: RemoteFrameHandle,
contextPC: BOOL]
RETURNS[bti: BodyIndex] =
{stb: SymbolTableBase;
world: World = remoteFrameHandle.world;
Lock[world];
[stb, bti] ← AcquireBTHandleFromRemoteFH[remoteFrameHandle, contextPC
! ANY => GOTO nope];
Unlock[world];
ReleaseSTB[stb];
EXITS nope => {Unlock[remoteFrameHandle.world]; RETURN[nullBodyIndex]}};

-- MOVE
AcquireBTHandleFromRemoteFH: PROC[fh: RemoteFrameHandle, contextPC: BOOL]
RETURNS[stb: SymbolTableBase, bti: BodyIndex] =
{ start: PrincOps.BytePC;
epn: CARDINAL;
remoteFrame: REF PrincOps.Frame = GetRemoteFrameHeader[fh];
framePC: PrincOps.BytePC = [(remoteFrame.pc - (IF contextPC THEN 0 ELSE 1))];

stb ← AcquireSTBFromRemoteGFH[[world: fh.world,
worldIncarnation: CurrentIncarnation[fh.world],
gfh: LOOPHOLE[remoteFrame.accesslink, ShortAddress]]];

[epn, start] ← GetRemoteEp[pc: framePC,
gf: [world: fh.world,
worldIncarnation: CurrentIncarnation[fh.world],
gfh: LOOPHOLE[remoteFrame.accesslink, ShortAddress]],
stb: stb
! UNWIND => ReleaseSTB[stb]];
bti ← RTTypesPrivate.ConvertCbti[base: stb,
pc: framePC,
start: start,
lastBti: LOOPHOLE[RTTypesPrivate.GetCBTI[stb, epn]]
! UNWIND => ReleaseSTB[stb]];
IF bti = rootBodyIndex THEN bti ← nullBodyIndex};

-- MOVE
GetRemoteEp: PUBLIC PROC [pc: PrincOps.BytePC,
gf: RemoteGlobalFrameHandle,
stb: SymbolTableBase]
RETURNS [ep: EVRange, start: PrincOps.BytePC] =
{ FindMaxEI: PROC RETURNS [max: EVRange] =
{ GetMaxX: PROC [bti: bx.BodyIndex] RETURNS [stop: BOOLEAN] =
{WITH stb SELECT FROM
t: SymbolTableBase.x =>
WITH t.e.bb[bti] SELECT FROM
Callable => IF ~inline THEN max ← MAX[max, entryIndex];
ENDCASE;
ENDCASE => ERROR;
RETURN[FALSE]};
GetMaxY: PROC [bti: by.BodyIndex] RETURNS [stop: BOOLEAN] =
{WITH stb SELECT FROM
t: SymbolTableBase.y =>
WITH t.e.bb[bti] SELECT FROM
Callable => IF ~inline THEN max ← MAX[max, entryIndex];
ENDCASE;
ENDCASE => ERROR;
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};

-- body of GetEp begins here
diff: CARDINALLAST[CARDINAL];
anyProcedure: BOOLEANFALSE;
FOR i: EVRange IN [0..FindMaxEI[]] DO
last: PrincOps.BytePC ← GetRemotePc[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;
RETURN};

-- MOVE
RemotePDToName: PUBLIC PROC[pd: RemotePD] RETURNS[ans: Rope.ROPE] =
{ stb: SymbolTableBase;
cbti: CallableBodyIndex;
pd ← UnwindRemoteIndirectProcDesc[pd];
IF pd.pd = 0 THEN RETURN[NIL];
[stb, cbti] ← AcquireCBTHandleFromRemotePD[pd];
ans ← AcquireRope[stb,
WITH stb SELECT FROM
t: SymbolTableBase.x =>
[x[t.e.seb[t.e.bb[NARROW[cbti, CallableBodyIndex.x].e].id].hash]],
t: SymbolTableBase.y =>
[y[t.e.seb[t.e.bb[NARROW[cbti, CallableBodyIndex.y].e].id].hash]],
ENDCASE => ERROR
! UNWIND => ReleaseSTB[stb]];
ReleaseSTB[stb];
RETURN[ans]};

RemoteSEDToName: PUBLIC PROC[sed: RemoteSED] RETURNS[ans: Rope.ROPENIL] =
{ item: PrincOpsRuntime.GFTItem;
gfh: RemoteGlobalFrameHandle ← nilRemoteGlobalFrameHandle;
stb: SymbolTableBase;
world: World = sed.world;

proc: PROC[stb: SymbolTableBase, isei: SymbolIdIndex]
RETURNS[stop: BOOLEAN] =
{WITH stb SELECT FROM
t: SymbolTableBase.x => RETURN[procX[t.e, NARROW[isei, SymbolIdIndex.x].e]];
t: SymbolTableBase.y => RETURN[procY[t.e, NARROW[isei, SymbolIdIndex.y].e]];
ENDCASE => ERROR};
procX: PROC[stb: bx.SymbolTableBase, isei: bx.SymbolIdIndex]
RETURNS[stop: BOOLEAN] =
{ tsei: bx.SymbolIndex;
IF stb.seb[isei].constant
AND stb.seb[tsei ← stb.UnderType[stb.seb[isei].idType]].typeTag = transfer
AND (SELECT stb.XferMode[tsei] FROM
error, signal => TRUE,
ENDCASE => FALSE)
AND CARDINAL[item.epbias * PrincOps.EPRange
+ LOOPHOLE[sed.sed, PrincOps.SignalDesc].ep] =
STInfoToEPN[LOOPHOLE[stb.seb[isei].idValue, PrincOps.SignalDesc]]
THEN {ans ← AcquireRope[[x[stb]], [x[stb.seb[isei].hash]]]; RETURN[TRUE]}
ELSE RETURN[FALSE]};
procY: PROC[stb: by.SymbolTableBase, isei: by.SymbolIdIndex]
RETURNS[stop: BOOLEAN] =
{ tsei: by.SymbolIndex;
IF stb.seb[isei].constant
AND stb.seb[tsei ← stb.UnderType[stb.seb[isei].idType]].typeTag = transfer
AND (SELECT stb.XferMode[tsei] FROM
error, signal => TRUE,
ENDCASE => FALSE)
AND CARDINAL[item.epbias * PrincOps.EPRange
+ LOOPHOLE[sed.sed, PrincOps.SignalDesc].ep] =
STInfoToEPN[LOOPHOLE[stb.seb[isei].idValue, PrincOps.SignalDesc]]
THEN {ans ← AcquireRope[[y[stb]], [y[stb.seb[isei].hash]]]; RETURN[TRUE]}
ELSE RETURN[FALSE]};

IF sed.sed = PrincOps.NullLink OR sed.sed = PrincOps.UnboundLink
THEN RETURN[NIL];
IF LOOPHOLE[sed.sed, CARDINAL] = 177777B
THEN RETURN["ERROR"];
IF LOOPHOLE[sed.sed, CARDINAL] = LOOPHOLE[UNWIND, CARDINAL]
THEN RETURN["UNWIND"];
IF LOOPHOLE[sed.sed, CARDINAL] = LOOPHOLE[ABORTED, CARDINAL]
THEN RETURN["ABORTED"];

{ ENABLE UNWIND => Unlock[world];
sei: SymbolRecordIndex;
Lock[world];
gfh ← GetRemoteGFHandle[world: world,
gfi: LOOPHOLE[sed.sed, PrincOps.SignalDesc].gfi];
CopyRead[world: world,
from: Long[world: world,
addr: LOOPHOLE[PrincOpsRuntime.GFT
+ LOOPHOLE[sed.sed, PrincOps.SignalDesc].gfi
* SIZE[PrincOpsRuntime.GFTItem],
ShortAddress]],
nwords: SIZE[PrincOpsRuntime.GFTItem],
to: @item];
stb ← AcquireSTBFromRemoteGFH[gfh];
sei ← WITH stb SELECT FROM
t: SymbolTableBase.x => [x[t.e.bb[bx.rootBodyIndex].type]],
t: SymbolTableBase.y => [y[t.e.bb[by.rootBodyIndex].type]],
ENDCASE => ERROR;
IF NOT NullISEI[LOOPHOLE[sei]] THEN
[] ← EnumerateRecordIseis[stb, sei, proc ! UNWIND => ReleaseSTB[stb]];
ReleaseSTB[stb];
Unlock[world]}};

RemoteStoreWords: PUBLIC PROC[from: LONG POINTER,
to: RemotePointer,
nWords: NAT] =
{ENABLE UNWIND => Unlock[to.world];
Lock[to.world];
CopyWrite[world: to.world, from: from, nwords: nWords, to: to.ptr];
Unlock[to.world]};

RemoteStoreWord: PUBLIC PROC[to: RemotePointer, value: CARDINAL] =
{ENABLE UNWIND => Unlock[to.world];
Lock[to.world];
Write[world: to.world, addr: to.ptr, value: value];
Unlock[to.world]};

RemoteStoreDoubleWord: PUBLIC PROC[to: RemotePointer, value: LONG CARDINAL] =
{ENABLE UNWIND => Unlock[to.world];
Lock[to.world];
LongWrite[world: to.world, addr: to.ptr, value: value];
Unlock[to.world]};

RemoteStoreFieldLong: PUBLIC PROC[ptr: RemotePointer,
field: RTCommon.Field,
value: LONG CARDINAL] =
{ENABLE UNWIND => Unlock[ptr.world];
val: LONG CARDINAL;
Lock[ptr.world];
val ← LongRead[world: ptr.world, addr: LOOPHOLE[ptr.ptr, Address]];
RTCommon.StoreFieldLong[ptr: @val, field: field, newValue: value];
LongWrite[world: ptr.world, addr: LOOPHOLE[ptr.ptr, Address], value: val];
Unlock[ptr.world];
};

GetRemoteWord: PUBLIC PROC[remotePointer: RemotePointer] RETURNS[ans: WORD] =
{ENABLE UNWIND => Unlock[remotePointer.world];
Lock[remotePointer.world];
ans ← Read[world: remotePointer.world, addr: remotePointer.ptr];
Unlock[remotePointer.world];
};

GetRemoteLC: PUBLIC PROC[remotePointer: RemotePointer] RETURNS[ans: LONG CARDINAL] =
{ENABLE UNWIND => Unlock[remotePointer.world];
Lock[remotePointer.world];
ans ← LongRead[world: remotePointer.world, addr: remotePointer.ptr];
Unlock[remotePointer.world];
};

GetRemoteWords: PUBLIC PROC[remotePointer: RemotePointer, nWords: NAT]
RETURNS[ans: WordSequence] =
{ENABLE UNWIND => Unlock[remotePointer.world];
Lock[remotePointer.world];
ans ← z.NEW[WordSequenceRecord[nWords]];
CopyRead[world: remotePointer.world,
from: remotePointer.ptr,
nwords: nWords,
to: LOOPHOLE[@ans[0], LONG POINTER]];
Unlock[remotePointer.world];
};

-- NOTE
RemoteSignalValues: PUBLIC PROC[tv: TypedVariable--catch Frame--]
RETURNS [message: CARDINAL, signal: PrincOps.SignalDesc, world: World] =
{rtr: REF TypedVariableRec ← NARROW[tv];
world ← GetWorld[tv];
WITH th: rtr.head SELECT FROM
fh =>
IF th.isCatchFrame
THEN {signallerFrameHandle: PrincOps.FrameHandle;
Runtime.ValidateFrame[th.fh];
signallerFrameHandle ← AMProcessBasic.ReturnLink[world, th.fh].frame;
message ← LOOPHOLE[signallerFrameHandle + SignallerFrameMessageOffset,
POINTER TO UNSPECIFIED]^;
signal ← LOOPHOLE[signallerFrameHandle + SignallerFrameSignalOffset,
POINTER TO PrincOps.SignalDesc]^;
RETURN}
ELSE ERROR Error[reason: typeFault, type: TVType[tv]];
remoteFH =>
IF th.isCatchFrame
THEN {ENABLE UNWIND => Unlock[world];
remoteSignallerFrameHandle: RemoteFrameHandle ← nilRemoteFrameHandle;
Lock[world];
ValidateRemoteFrame[th.remoteFrameHandle];
remoteSignallerFrameHandle
← [world: world,
worldIncarnation: CurrentIncarnation[world],
fh: LOOPHOLE[AMProcessBasic.ReturnLink
[world,
LOOPHOLE[th.remoteFrameHandle.fh,
PrincOps.FrameHandle]],
ShortAddress]];
message ← Read[world: world,
addr: Long[world: world,
addr: remoteSignallerFrameHandle.fh
+ SignallerFrameMessageOffset]];
signal ← LOOPHOLE
[Read[world: world,
addr: Long[world: world,
addr: remoteSignallerFrameHandle.fh
+ SignallerFrameSignalOffset]],
PrincOps.SignalDesc];
Unlock[world];
RETURN}
ELSE ERROR Error[reason: typeFault, type: TVType[tv]];
ENDCASE => ERROR Error[reason: typeFault, type: TVType[tv]]};

STInfoToEPN: PROC[cl: PrincOps.SignalDesc] RETURNS[CARDINAL] =
{RETURN[(cl.gfi - 1) * PrincOps.EPRange + cl.ep]};

Card: PROC[pc: PrincOps.BytePC] RETURNS[CARDINAL] =
{RETURN[LOOPHOLE[pc, CARDINAL]]};

END.