DIRECTORY
AMBridge
USING[
GFHFromTV, IsRemote, RemoteGFHFromTV, GetWorld, TVForGFHReferent, TVForRemoteGFHReferent, RemoteGlobalFrameHandle, nilRemoteGlobalFrameHandle
],
AMModel USING[SectionObj, SectionClass, Context],
AMModelLocation USING[CodeLocation],
AMModelPrivate
USING[
SectionRec, EPI, FGIToEPI, FGIToFirstPC, EPIToFirstPC, EPIToLastPC, PCOffset, GetModuleSTB
],
AMTypes USING[Error],
BcdDefs USING[VersionStamp, MTIndex, FTSelf, BcdBase],
LoadState
USING[
local, ModuleInfo, ConfigInfo, Acquire, Release, EnumerateAllModules, GlobalFrameToModule, Handle, ConfigID, ModuleIndex
],
PrincOps USING[FrameCodeBase, BytePC, GlobalFrameHandle],
RTSymbolDefs USING[SymbolTableBase],
RTSymbols USING[ReleaseSTB],
RTTypesPrivate USING[GetPc],
RTTypesRemotePrivate
USING[
GetRemoteGFHeader, GetRemotePc, AcquireRemoteBCD, ReleaseRemoteBCD
],
Table USING[Base],
WorldVM
USING[
World, NoWorld, LocalWorld, Lock, Unlock, Loadstate, CurrentIncarnation, ShortAddress
];
AMModelLocationImpl:
PROGRAM
IMPORTS AMBridge, AMModel, AMModelPrivate, AMTypes, LoadState, RTSymbols, RTTypesPrivate, RTTypesRemotePrivate, WorldVM
EXPORTS AMModel, AMModelLocation, AMModelPrivate
TYPEs
either binder output bundle for a config, or compiler output bundle for a prog module, DEFs module, proc, or statement
Section: TYPE = REF SectionObj;
SectionObj: PUBLIC TYPE = SectionRec;
EntryLocations:
PUBLIC
PROC[section: Section]
RETURNS[world: World, list: LIST OF CodeLocation ← NIL] =
{[world: world, list: list] ← GetLocations[section]};
ExitLocations:
PUBLIC
PROC[section: Section]
RETURNS[world: World, list: LIST OF CodeLocation ← NIL] =
{[world: world, list: list] ← GetLocations[section: section, entry: FALSE]};
GetLocations:
PROC[section: Section, entry:
BOOL ←
TRUE]
RETURNS[world: World ← NoWorld[], list: LIST OF CodeLocation ← NIL] = {
epi: EPI;
firstPC: PCOffset;
progContexts: LIST OF Context ← NIL;
context: Context ← NIL;
version: BcdDefs.VersionStamp;
SELECT SectionClass[section]
FROM
statement => {
statementSect: REF statement SectionObj = NARROW[section];
context ← statementSect.prog.someGFHTV;
IF context = NIL THEN RETURN; -- section is not loaded
version ← statementSect.prog.versionStamp;
world ← GetWorld[context];
IF world = LocalWorld[]
THEN {
bcd: BcdDefs.BcdBase = GetLocalBCD[GFHFromTV[context]];
stb: SymbolTableBase ← GetModuleSTB[bcd, statementSect.prog.versionStamp];
{
ENABLE
UNWIND => ReleaseSTB[stb];
epi ← FGIToEPI[stb, statementSect.fgtIndex];
firstPC ← FGIToFirstPC[stb, statementSect.fgtIndex];
}; -- end ENABLE UNWIND
ReleaseSTB[stb];
} -- end IF world = LocalWorld[]
ELSE {
-- remote world case
bcd: BcdDefs.BcdBase = GetRemoteBCD[RemoteGFHFromTV[context]];
stb: SymbolTableBase ← GetModuleSTB[bcd, statementSect.prog.versionStamp
! UNWIND => ReleaseRemoteBCD[bcd]];
ReleaseRemoteBCD[bcd];
{
ENABLE
UNWIND => ReleaseSTB[stb];
epi ← FGIToEPI[stb, statementSect.fgtIndex];
firstPC ← FGIToFirstPC[stb, statementSect.fgtIndex];
}; -- end ENABLE UNWIND
ReleaseSTB[stb];
};
};
proc => {
procSect: REF proc SectionObj = NARROW[section];
context ← procSect.prog.someGFHTV;
IF context = NIL THEN RETURN; -- section is not loaded
version ← procSect.prog.versionStamp;
epi ← procSect.entryPointIndex;
world ← GetWorld[context];
IF world = LocalWorld[]
THEN {
bcd: BcdDefs.BcdBase = GetLocalBCD[GFHFromTV[context]];
stb: SymbolTableBase ← GetModuleSTB[bcd, procSect.prog.versionStamp];
{
ENABLE
UNWIND => ReleaseSTB[stb];
IF entry THEN firstPC ← EPIToFirstPC[stb, epi, TRUE]
ELSE firstPC ← EPIToLastPC[stb, epi];
}; -- end ENABLE UNWIND
ReleaseSTB[stb];
}
ELSE {
-- remote world case
bcd: BcdDefs.BcdBase = GetRemoteBCD[RemoteGFHFromTV[context]];
stb: SymbolTableBase ← GetModuleSTB[bcd, procSect.prog.versionStamp
! UNWIND => ReleaseRemoteBCD[bcd]];
ReleaseRemoteBCD[bcd];
{
ENABLE
UNWIND => ReleaseSTB[stb];
IF entry
THEN firstPC ← EPIToFirstPC[stb, epi,
TRUE]
ELSE firstPC ← EPIToLastPC[stb, epi];
}; -- end ENABLE UNWIND
ReleaseSTB[stb];
};
};
ENDCASE =>
ERROR Error[
reason: typeFault,
msg: "EntryLocation applied to a section neither for a statement nor a proc"];
progContexts ← ProgContextsForVersion[world: world, version: version];
was: progContexts ← SourceSection[SectionSource[section], RootContext[world]].contexts; could be (restrict to one gf): progContexts ← CONS[context, NIL]; want to find all gf's for the indicated section
IF progContexts = NIL THEN ERROR;
Here with epi, firstPC and all progContext loadings of the section in the specified world
FOR contextList: LIST OF Context ← progContexts, contextList.rest UNTIL contextList = NIL
DO
codeBase: PrincOps.FrameCodeBase;
pc: PrincOps.BytePC;
context: Context = contextList.first;
found: BOOL ← FALSE;
IF IsRemote[context]
THEN {
codeBase ← GetRemoteGFHeader[RemoteGFHFromTV[context]].code;
pc ← [firstPC + GetRemotePc[RemoteGFHFromTV[context], epi]];
}
ELSE {
codeBase ← GFHFromTV[context].code;
pc ← [firstPC + GetPc[GFHFromTV[context], epi]];
};
FOR cll:
LIST
OF CodeLocation ← list, cll.rest
UNTIL cll =
NIL
DO IF cll.first.codeBase = codeBase THEN {found ← TRUE; EXIT};
ENDLOOP;
IF NOT found THEN list ← CONS[[codeBase: codeBase, pc: pc], list];
ENDLOOP;
}; -- end GetLocations
ProgContextsForVersion:
PROC[world: World, version: BcdDefs.VersionStamp]
RETURNS[contexts: LIST OF Context ← NIL] = {
IF world = LocalWorld[]
THEN {
forEachModule:
PROC[ci: LoadState.ConfigID, mi: LoadState.ModuleIndex]
RETURNS[stop: BOOL ← FALSE] = {
bcd: BcdDefs.BcdBase = LoadState.local.ConfigInfo[ci].bcd;
ftb: Table.Base ← LOOPHOLE[bcd + bcd.ftOffset];
mtb: Table.Base ← LOOPHOLE[bcd + bcd.mtOffset];
gfh: GlobalFrameHandle;
mti: BcdDefs.MTIndex;
[gfh: gfh, mti: mti] ← LoadState.local.ModuleInfo[ci, mi];
IF NOT loadStateHeld THEN ERROR;
IF (
IF mtb[mti].file = BcdDefs.FTSelf
THEN bcd.version
ELSE ftb[mtb[mti].file].version) = version
THEN contexts ← CONS[TVForGFHReferent[gfh], contexts];
};
loadStateHeld: BOOL ← FALSE;
LoadState.local.Acquire[];
loadStateHeld ← TRUE;
[] ← LoadState.local.EnumerateAllModules[newestFirst, forEachModule
! ANY => {LoadState.local.Release[]; loadStateHeld ← FALSE}];
IF loadStateHeld THEN LoadState.local.Release[];
} -- end local case of ProgContextsForVersion
ELSE {
-- remote world case of ProgContextsForVersion
Lock[world];
{
ENABLE
UNWIND => Unlock[world];
forEachModule:
PROC[ci: LoadState.ConfigID, mi: LoadState.ModuleIndex]
RETURNS[stop: BOOL ← FALSE] = {
bcd: BcdDefs.BcdBase
= AcquireRemoteBCD
[world, WorldVM.CurrentIncarnation[world], newState.ConfigInfo[ci].bcd];
{
ENABLE
UNWIND => ReleaseRemoteBCD[bcd];
ftb: Table.Base ← LOOPHOLE[bcd + bcd.ftOffset];
mtb: Table.Base ← LOOPHOLE[bcd + bcd.mtOffset];
gfh: GlobalFrameHandle;
rgfh: RemoteGlobalFrameHandle ← nilRemoteGlobalFrameHandle;
mti: BcdDefs.MTIndex;
[gfh: gfh, mti: mti] ← newState.ModuleInfo[ci, mi];
rgfh
← [world,
WorldVM.CurrentIncarnation[world],
LOOPHOLE[gfh, WorldVM.ShortAddress]];
IF NOT loadStateHeld THEN ERROR;
IF (
IF mtb[mti].file = BcdDefs.FTSelf
THEN bcd.version
ELSE ftb[mtb[mti].file].version) = version
THEN contexts ← CONS[TVForRemoteGFHReferent[rgfh], contexts];
}; -- end ENABLE UNWIND => ReleaseRemoteBCD[bcd];
ReleaseRemoteBCD[bcd];
}; -- end forEachModule
loadStateHeld: BOOL ← FALSE;
newState: LoadState.Handle = WorldVM.Loadstate[world];
newState.Acquire[];
loadStateHeld ← TRUE;
[] ← newState.EnumerateAllModules[newestFirst, forEachModule
! ANY => {newState.Release[]; loadStateHeld ← FALSE}];
IF loadStateHeld THEN newState.Release[];
}; -- end ENABLE UNWIND => Unlock[world];
Unlock[world];
}; -- end remote world case of ProgContextsForVersion
}; -- end ProgContextsForVersion
GetRemoteBCD:
PUBLIC
PROC[rgfh: RemoteGlobalFrameHandle]
RETURNS[bcd: BcdDefs.BcdBase ← NIL] = {
h: LoadState.Handle;
WorldVM.Lock[rgfh.world];
h ← WorldVM.Loadstate[rgfh.world ! UNWIND => WorldVM.Unlock[rgfh.world]];
h.Acquire[];
{
ENABLE
UNWIND => {h.Release[]; WorldVM.Unlock[rgfh.world]};
gfh: GlobalFrameHandle = LOOPHOLE[rgfh.gfh];
bcd ← AcquireRemoteBCD[
rgfh.world,
WorldVM.CurrentIncarnation[rgfh.world],
h.ConfigInfo[h.GlobalFrameToModule[gfh].config].bcd
];
}; -- end ENABLE UNWIND
h.Release[];
WorldVM.Unlock[rgfh.world];
};
GetLocalBCD:
PUBLIC
PROC[gfh: GlobalFrameHandle]
RETURNS[bcd: BcdDefs.BcdBase] = {
LoadState.local.Acquire[];
{
ENABLE
UNWIND => LoadState.local.Release[];
bcd ← LoadState.local.ConfigInfo[LoadState.local.GlobalFrameToModule[gfh].config].bcd;
};
LoadState.local.Release[];
};
This guy uses RTTypesRemotePrivate.AcquireRemoteBCD.
BEWARE. Don't forget to release it via RTTypesRemotePrivate.ReleaseRemoteBCD
GetRemoteBCD: PUBLIC PROC[world: World, rgfi: PrincOps.GFTIndex]
RETURNS[bcd: BcdDefs.BcdBase ← NIL] = {
Lock[world];
{ ENABLE UNWIND => Unlock[world];
oldState: PilotLoadStateFormat.LoadState;
newState: REF PilotLoadStateFormat.LoadStateObject;
loadstateHeld: BOOL ← FALSE;
newState ← Loadstate[world];
[] ← PilotLoadStateOps.InputLoadState[];
loadstateHeld ← TRUE;
oldState ← PilotLoadStatePrivate.InstallLoadState[LOOPHOLE[newState]];
no error raised
bcd ← AcquireRemoteBCD[
world,
PilotLoadStateOps.AcquireBcd[PilotLoadStateOps.MapRealToConfig[rgfi].config]
! ANY => {
[] ← PilotLoadStatePrivate.InstallLoadState[oldState];
PilotLoadStateOps.ReleaseLoadState[];
loadstateHeld ← FALSE;
}];
IF loadstateHeld THEN {
[] ← PilotLoadStatePrivate.InstallLoadState[oldState];
PilotLoadStateOps.ReleaseLoadState[];
loadstateHeld ← FALSE;
};
IF bcd = NIL THEN ERROR;
}; end ENABLE UNWIND => Unlock[world];
Unlock[world];
}; end GetRemoteBCD
}.