AMModelSourceImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
created by Rovner, December 12, 1983 11:12 am
Russ Atkinson (RRA) November 12, 1985 2:52:54 pm PST
DIRECTORY
AMBridge USING [GetWorld, GetWorldIncarnation, GFHFromTV, IsRemote, nilRemoteGlobalFrameHandle, RemoteGFHFromTV, RemoteGlobalFrameHandle, TVForGFHReferent, TVForProc, TVForRemoteGFHReferent, TVForRemoteProc, TVToProc, TVToRemoteProc],
AMFiles USING [OpenIt],
AMModel USING [CharIndex, Class, Context, ContextChildren, ContextSection, Section, SectionClass, SectionObj, SectionSource, SectionVersion, Source, SourceClass, SourceFileName, SourceObj],
AMModelBridge USING [LoadedSection, ContextForFrame, FrameFromContext],
AMModelLocation USING [CodeLocation],
AMModelPrivate USING [CharIndexToFGI, ConfigContext, EPI, EPIToFirstPC, EPIToLastPC, FGIndex, FGIToEPI, FGIToFirstPC, FGNull, FindMatchingGlobalFrames, PCOffset, ProgPCToFGI, RefTVRec, SectionRec],
AMTypes USING [Error, GlobalParent, TV, TVType],
BasicTime USING [FromNSTime, ToNSTime],
BcdDefs USING [BcdBase, FTSelf, MTHandle, MTIndex, VersionStamp],
BcdOps USING [ProcessModules],
FS USING [OpenFile, nullOpenFile, GetInfo, Close],
IO USING [PutFR],
LoadState USING [Acquire, ConfigID, ConfigInfo, EnumerateAllModules, GlobalFrameToModule, Handle, local, ModuleIndex, ModuleInfo, nullConfig, Release],
PrincOps USING [BytePC, ControlLink, EPRange, FrameCodeBase, GlobalFrameHandle, ProcDesc],
PrincOpsUtils USING [GlobalFrameAndEntryPoint],
RemotePrincOpsUtils USING [RemoteGlobalFrameAndEntryPoint],
Rope USING [Concat, Equal, Flatten, Length, Match, ROPE],
RuntimeError USING [UNCAUGHT],
RTSymbolDefs USING [SymbolTableBase, SymbolTableHandle, nullHandle, nullBase],
RTSymbols USING [ReleaseSTB, AcquireSTBFromSGI, AcquireSTB, GetSTHForModule],
RTSymbolsPrivate USING [AcquireBCDFromVersion, ReleaseBCD],
RTTypesPrivate USING [GetPc],
RTTypesRemotePrivate USING [AcquireRemoteBCD, GetRemoteGFHeader, GetRemotePc, ReleaseRemoteBCD],
SafeStorage USING [fhType, gfhType, Type],
Table USING [Base],
WorldVM USING [CurrentIncarnation, Loadstate, LocalWorld, Lock, NoWorld, ShortAddress, Unlock, World];
AMModelSourceImpl: PROGRAM
IMPORTS AMBridge, AMFiles, AMModel, AMModelBridge, AMModelPrivate, AMTypes, BasicTime, BcdOps, FS, IO, LoadState, PrincOpsUtils, RemotePrincOpsUtils, Rope, RTSymbols, RTSymbolsPrivate, RTTypesPrivate, RTTypesRemotePrivate, RuntimeError, WorldVM
EXPORTS AMModel, AMModelBridge, AMModelLocation, AMModelPrivate
= { OPEN AMBridge, AMModel, AMModelBridge, AMModelPrivate, AMTypes, PrincOps, RTSymbolDefs, RTSymbols, RTTypesPrivate, RTTypesRemotePrivate;
TYPEs
CodeLocation: TYPE = AMModelLocation.CodeLocation;
LoadedSection: TYPE = AMModelBridge.LoadedSection;
A LoadedSection is a convenience for clients of AMModelBridge. Each represents one of:
loaded compiler output bundle for a prog module [prog, prog]
loaded compiler output bundle for a proc [proc, prog]
loaded compiler output bundle for a statement [statement, prog]
ROPE: TYPE = Rope.ROPE;
Section: TYPE = REF SectionObj;
SectionObj: PUBLIC TYPE = AMModelPrivate.SectionRec;
either binder output bundle for a config, or compiler output bundle for a prog module, DEFs module, proc, or statement
TV: TYPE = AMTypes.TV;
World: TYPE = WorldVM.World;
fhType: SafeStorage.Type = SafeStorage.fhType;
gfhType: SafeStorage.Type = SafeStorage.gfhType;
PROCs
... dealing with Source
FileSource: PUBLIC PROC [fileName: ROPE, class: --model, prog, interface--Class] RETURNS [s: Source ← NIL] = {
f: FS.OpenFile ← FS.nullOpenFile;
IF class = model
THEN {
IF NOT Rope.Match["*.config*", fileName, FALSE]
THEN fileName ← fileName.Concat[".config"];
}
ELSE {
IF NOT Rope.Match["*.mesa*", fileName, FALSE]
THEN fileName ← fileName.Concat[".mesa"];
};
f ← AMFiles.OpenIt[fileName].openFile;
IF f # FS.nullOpenFile
THEN {
s ← NEW[SourceObj ← [
fileName: fileName,
class: class,
versionStamp: [0, 0, BasicTime.ToNSTime[FS.GetInfo[f].created]],
sourceRange: entire[]]];
FS.Close[f];
};
};
SourceSection: PUBLIC PROC [source: Source, context: --worldRoot or model--Context] RETURNS [section: Section ← NIL, contexts: LIST OF --prog--Context ← NIL] = {
Use SourceSection to figure out (given a proc or statement source location)
where to place a breakpoint.
The list of prog Contexts returned by SourceSection is meaningful for
prog, proc and statement sources. It will be ordered "most-recently-loaded first".
Strictly speaking, a source can have multiple sections: one for each set of "SectionParams".
Someday we'll accommodate such, but not this week.
NOTE context = NIL oughta mean to find the section even though it's not loaded
SELECT SourceClass[source] FROM
statement => {
[section, contexts]
← SourceSection [
NEW[SourceObj ← [fileName: source.fileName,
class: prog,
versionStamp: source.versionStamp,
sourceRange: entire[]]],
context];
section ← NEW[SectionObj ← [statement[prog: NARROW[section], fgtIndex: SourceToFGIandEPI[source, NARROW[section]].fgi]]];
};
proc => {
[section, contexts]
← SourceSection [
NEW[SourceObj ← [fileName: source.fileName,
class: prog,
versionStamp: source.versionStamp,
sourceRange: entire[]]],
context];
section ← NEW[SectionObj ← [proc[prog: NARROW[section], entryPointIndex: SourceToFGIandEPI[source, NARROW[section]].epi]]];
};
prog => {
look thru all global frames in context for ones with the source name.
Construct section for the first one found, thereafter check version stamp.
For each found, cons onto contexts
WITH context SELECT FROM
tv: RefTVRec => {
SELECT TVType[tv] FROM
gfhType => {
section ← ContextSection[context];
IF Rope.Equal[SourceFileName[source], SourceFileName[SectionSource[section]], FALSE]
THEN contexts ← CONS[context, NIL]
ELSE section ← NIL;
RETURN;
};
fhType => {
[section, contexts] ← SourceSection[source, GlobalParent[tv]];
RETURN;
};
ENDCASE => ERROR Error[typeFault];
};
mc: ConfigContext => {
IF mc.configIndex = LoadState.nullConfig
THEN {
inner: PROC [name: ROPE, context: AMModel.Context] RETURNS [stop: BOOLFALSE] = TRUSTED {
temp: Section ← AMModel.ContextSection[context];
source: AMModel.Source ← AMModel.SectionSource[temp];
IF source.versionStamp = sourceVersion THEN {
This context is from the given source, so we keep it
contexts ← CONS[context, contexts];
IF section # NIL THEN
We must check for multiple sections from the same source
IF SectionVersion[temp] # SectionVersion[section] THEN
ERROR Error[reason: notImplemented, msg: "different sections for the same source"];
section ← temp;
};
};
sourceVersion: BcdDefs.VersionStamp ← source.versionStamp;
world: WorldVM.World ← mc.world;
shortName: ROPE ← source.fileName;
IF Rope.Match["*.mesa", shortName, FALSE] THEN
shortName ← Rope.Flatten[shortName, 0, Rope.Length[shortName]-5];
IF world = NIL THEN world ← WorldVM.LocalWorld[];
[] ← AMModelPrivate.FindMatchingGlobalFrames[world, shortName, inner];
}
ELSE {
proc: PROC [context: Context] RETURNS [stop: BOOLFALSE] = {
IF Rope.Equal[SourceFileName[source], SourceFileName[SectionSource[ContextSection[context]]], FALSE] THEN {
SELECT TRUE FROM
section = NIL => section ← ContextSection[context];
SectionVersion[ContextSection[context]] # SectionVersion[section] => {
ERROR Error[reason: notImplemented, msg: "different sections for the same source"];
};
ENDCASE;
contexts ← CONS[context, contexts];
};
};
[] ← ContextChildren[context, proc];
};
};
ENDCASE => ERROR
};
model =>
ERROR AMTypes.Error[reason: notImplemented, msg: "SourceSection[model source]"];
interface =>
ERROR AMTypes.Error[reason: notImplemented, msg: "SourceSection[interface source]"];
ENDCASE => ERROR;
IF section = NIL THEN {
No symbols for the given source
AMTypes.Error[noSymbols,
IO.PutFR["for source file %g of %g",
[rope[source.fileName]],
[time[BasicTime.FromNSTime[source.versionStamp.time]]] ]];
};
};
GetModuleSTB: PUBLIC PROC [bcd: BcdDefs.BcdBase, versionStamp: BcdDefs.VersionStamp] RETURNS [stb: SymbolTableBase ← nullBase] = {
FindModule: PROC [mth: BcdDefs.MTHandle, mti: BcdDefs.MTIndex] RETURNS [stop: BOOLFALSE] = {
version: BcdDefs.VersionStamp ← IF mth.file = BcdDefs.FTSelf
THEN bcd.version ELSE ftb[mth.file].version;
IF version = versionStamp THEN {
stb ← AcquireSTBFromSGI[bcd, mth.sseg];
RETURN[TRUE]};
};
start GetModuleSTB here
sth: SymbolTableHandle ← nullHandle;
ftb: Table.Base = LOOPHOLE[bcd + bcd.ftOffset];
sth ← GetSTHForModule[versionStamp, NIL, NIL
! RuntimeError.UNCAUGHT, AMTypes.Error => CONTINUE];
IF sth = nullHandle
THEN [] ← BcdOps.ProcessModules[bcd, FindModule]
ELSE stb ← AcquireSTB[sth];
};
Formerly in AMModelBridgeImpl
LoadedSectionForProc: PUBLIC PROC [tv: AMTypes.TV--proc--] RETURNS [ans: LoadedSection ← [NIL, NIL, [0]]] = {
c: Context;
s: Section;
ep: CARDINAL;
gf: AMTypes.TV ← AMTypes.GlobalParent[tv];
ans.context ← AMModelBridge.ContextForFrame[gf];
c ← ans.context;
s ← ContextSection[c];
IF AMBridge.IsRemote[tv]
THEN {
world: WorldVM.World = AMBridge.GetWorld[tv];
rgfh: AMBridge.RemoteGlobalFrameHandle ← AMBridge.nilRemoteGlobalFrameHandle;
gfh: PrincOps.GlobalFrameHandle;
[gfh, ep] ← RemotePrincOpsUtils.RemoteGlobalFrameAndEntryPoint [world, AMBridge.TVToRemoteProc[tv].pd];
rgfh ← [world, WorldVM.CurrentIncarnation[world], LOOPHOLE[gfh]];
ans.pc ← RTTypesRemotePrivate.GetRemotePc[rgfh, ep];
}
ELSE {
gfh: PrincOps.GlobalFrameHandle;
[gfh, ep] ← PrincOpsUtils.GlobalFrameAndEntryPoint[ LOOPHOLE[AMBridge.TVToProc[tv]]];
ans.pc ← RTTypesPrivate.GetPc[gfh, ep];
};
ans.section ← NEW[SectionObj ← [proc[prog: NARROW[s], entryPointIndex: ep, procTV: NARROW[tv]]]];
};
LoadedSectionForProgPC: PUBLIC PROC [prog: Context, pc: BytePC] RETURNS [ans: LoadedSection ← [NIL, NIL, [0]]] = {
s: Section = ContextSection[prog];
ctx: TV ← AMModelBridge.FrameFromContext[prog];
ans.context ← prog;
ans.section ← NEW[SectionObj ← [statement [
prog: NARROW[s],
fgtIndex: AMModelPrivate.ProgPCToFGI[ctx, pc]]]];
ans.pc ← pc;
};
ProcFromLoadedSection: PUBLIC PROC [proc: LoadedSection] RETURNS [AMTypes.TV] = {
s: Section = proc.section;
sr: REF proc SectionObj ← NARROW[s];
IF sr.procTV # NIL
THEN RETURN[sr.procTV]
ELSE {
ctx: TV ← AMModelBridge.FrameFromContext[proc.context];
IF AMBridge.IsRemote[ctx]
THEN {
pd: PrincOps.ProcDesc ← PrincOps.ControlLink[procedure[gfi: 0, ep: 0, tag: TRUE]];
pd.gfi ← RTTypesRemotePrivate.GetRemoteGFHeader[AMBridge.RemoteGFHFromTV[ctx]].gfi + sr.entryPointIndex/PrincOps.EPRange;
pd.ep ← sr.entryPointIndex MOD PrincOps.EPRange;
RETURN[AMBridge.TVForRemoteProc[[
world: AMBridge.GetWorld[ctx],
worldIncarnation: AMBridge.GetWorldIncarnation[ctx],
pd: LOOPHOLE[pd]]]];
}
ELSE {
pd: PrincOps.ProcDesc ← PrincOps.ControlLink[procedure[gfi: 0, ep: 0, tag: TRUE]];
pd.gfi ← AMBridge.GFHFromTV[ctx].gfi + sr.entryPointIndex/PrincOps.EPRange;
pd.ep ← sr.entryPointIndex MOD PrincOps.EPRange;
RETURN[AMBridge.TVForProc[LOOPHOLE[pd]]];
};
};
};
Formerly in AMModelLocationImpl
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: BOOLTRUE] RETURNS [world: World ← WorldVM.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];
{
stb: SymbolTableBase ← STBforContext[context, statementSect.prog.versionStamp];
{ ENABLE UNWIND => ReleaseSTB[stb];
epi ← FGIToEPI[stb, statementSect.fgtIndex];
firstPC ← FGIToFirstPC[stb, statementSect.fgtIndex];
};
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];
{
stb: SymbolTableBase ← STBforContext[context, version];
{ ENABLE UNWIND => ReleaseSTB[stb];
IF entry
THEN firstPC ← EPIToFirstPC[stb, epi, TRUE]
ELSE firstPC ← EPIToLastPC[stb, epi];
};
ReleaseSTB[stb];
};
};
ENDCASE => ERROR Error[reason: typeFault, msg: "EntryLocation misapplied"];
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: BOOLFALSE;
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;
};
ProgContextsForVersion: PROC [world: World, version: BcdDefs.VersionStamp] RETURNS [contexts: LIST OF Context ← NIL] = {
IF world = WorldVM.LocalWorld[]
THEN {
forEachModule: PROC [ci: LoadState.ConfigID, mi: LoadState.ModuleIndex]
RETURNS [stop: BOOLFALSE] = {
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: BOOLFALSE;
LoadState.local.Acquire[];
loadStateHeld ← TRUE;
[] ← LoadState.local.EnumerateAllModules[newestFirst, forEachModule
! RuntimeError.UNCAUGHT, AMTypes.Error, UNWIND =>
IF loadStateHeld THEN {LoadState.local.Release[]; loadStateHeld ← FALSE}];
IF loadStateHeld THEN LoadState.local.Release[];
}
ELSE {
remote world case of ProgContextsForVersion
WorldVM.Lock[world];
{ ENABLE UNWIND => WorldVM.Unlock[world];
forEachModule: PROC [ci: LoadState.ConfigID, mi: LoadState.ModuleIndex]
RETURNS [stop: BOOLFALSE] = {
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];
};
ReleaseRemoteBCD[bcd];
};
loadStateHeld: BOOLFALSE;
newState: LoadState.Handle = WorldVM.Loadstate[world];
newState.Acquire[];
loadStateHeld ← TRUE;
[] ← newState.EnumerateAllModules[newestFirst, forEachModule
! RuntimeError.UNCAUGHT, AMTypes.Error, UNWIND =>
IF loadStateHeld THEN {newState.Release[]; loadStateHeld ← FALSE}];
IF loadStateHeld THEN newState.Release[];
};
WorldVM.Unlock[world];
};
};
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
];
};
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[];
};
Utilities
SourceToFGIandEPI: PROC [source: Source, prog: REF prog SectionObj] RETURNS [fgi: FGIndex ← FGNull, epi: EPI ← 0] = {
[prog module bcd, CharIndex] => FGIndex (wrt prog module bcd) & epi
stb: SymbolTableBase;
IF prog.someGFHTV # NIL
THEN stb ← STBforContext[prog.someGFHTV, prog.versionStamp]
ELSE {
bcd: BcdDefs.BcdBase = RTSymbolsPrivate.AcquireBCDFromVersion[
versionStamp: prog.versionStamp,
shortFileNameHint: Rope.Concat[prog.moduleName, ".bcd"]];
stb: SymbolTableBase ← GetModuleSTB[bcd, prog.versionStamp
! UNWIND => RTSymbolsPrivate.ReleaseBCD[bcd]];
RTSymbolsPrivate.ReleaseBCD[bcd];
};
{
ENABLE UNWIND => ReleaseSTB[stb];
fgi ← CharIndexToFGI[stb,
(WITH s: source SELECT FROM field => s.firstCharIndex ENDCASE => 0)];
epi ← FGIToEPI[stb, fgi];
};
ReleaseSTB[stb];
};
STBforContext: PROC [ctx: TV, version: BcdDefs.VersionStamp] RETURNS [stb: SymbolTableBase] = {
world: World = AMBridge.GetWorld[ctx];
IF world = WorldVM.LocalWorld[]
THEN {
bcd: BcdDefs.BcdBase = GetLocalBCD[AMBridge.GFHFromTV[ctx]];
Note, a loaded local bcd does not need release
stb ← GetModuleSTB[bcd, version];
}
ELSE {
bcd: BcdDefs.BcdBase = GetRemoteBCD[AMBridge.RemoteGFHFromTV[ctx]];
stb ← GetModuleSTB[bcd, version
! UNWIND => RTTypesRemotePrivate.ReleaseRemoteBCD[bcd]];
RTTypesRemotePrivate.ReleaseRemoteBCD[bcd];
};
};
}.