<> <> <> <> 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; <> CodeLocation: TYPE = AMModelLocation.CodeLocation; LoadedSection: TYPE = AMModelBridge.LoadedSection; <> <> <> <> ROPE: TYPE = Rope.ROPE; Section: TYPE = REF SectionObj; SectionObj: PUBLIC TYPE = AMModelPrivate.SectionRec; <> TV: TYPE = AMTypes.TV; World: TYPE = WorldVM.World; fhType: SafeStorage.Type = SafeStorage.fhType; gfhType: SafeStorage.Type = SafeStorage.gfhType; <> <<... 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] = { <> <> <> <> <> <> <> 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 => { <> <> <> 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: BOOL _ FALSE] = TRUSTED { temp: Section _ AMModel.ContextSection[context]; source: AMModel.Source _ AMModel.SectionSource[temp]; IF source.versionStamp = sourceVersion THEN { <> contexts _ CONS[context, contexts]; IF section # NIL THEN <> 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: BOOL _ FALSE] = { 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 { <> 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: BOOL _ FALSE] = { 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]}; }; <> 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]; }; <> 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]]]; }; }; }; <> 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 _ 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]; <> IF progContexts = NIL THEN ERROR; <<>> <> 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; }; 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: 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 ! RuntimeError.UNCAUGHT, AMTypes.Error, UNWIND => IF loadStateHeld THEN {LoadState.local.Release[]; loadStateHeld _ FALSE}]; IF loadStateHeld THEN LoadState.local.Release[]; } ELSE { <> WorldVM.Lock[world]; { ENABLE UNWIND => WorldVM.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]; }; ReleaseRemoteBCD[bcd]; }; loadStateHeld: BOOL _ FALSE; 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[]; }; <> 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]]; <> stb _ GetModuleSTB[bcd, version]; } ELSE { bcd: BcdDefs.BcdBase = GetRemoteBCD[AMBridge.RemoteGFHFromTV[ctx]]; stb _ GetModuleSTB[bcd, version ! UNWIND => RTTypesRemotePrivate.ReleaseRemoteBCD[bcd]]; RTTypesRemotePrivate.ReleaseRemoteBCD[bcd]; }; }; }.