LocalCirioImpl.mesa
Copyright Ó 1990, 1991, 1992 by Xerox Corporation. All rights reserved.
Sturgis, April 20, 1990 3:25 pm PDT
Last changed by Theimer on November 28, 1989 3:36:23 pm PST
Last tweaked by Mike Spreitzer on July 24, 1992 6:14 pm PDT
Linda Howe January 3, 1990 4:09:35 pm PST
Coolidge, July 18, 1990 10:21 am PDT
Laurie Horton, March 31, 1992 12:48 pm PST
Philip James, February 24, 1992 11:42 am PST
Udagawa, February 12, 1991 9:03 pm PST
Willie-s, July 27, 1992 5:48 pm PDT
DIRECTORY
AmpersandContext USING[CreateAnAmpersandContext, MakeNodeFromNode, StripAMNode],
BasicTime USING[Now],
CCTypes USING[CC, CCError, CCErrorCase, CreateCedarCompilerContext, LocalCedarTargetWorld, LocalCedarTargetWorldBody, RegisterLocalCedarTargetWorld],
CedarCode USING[GetNodeRepresentation, GetTypeOfNode, LoadThroughIndirectNode, SelectFieldFromNode, StoreThroughIndirectNode],
CirioBackstop USING[Protect],
CirioBreakAccess USING[CirioBreakSet, CreateCirioBreakSet, ClearAllBreaks, ClearBreakAtAbsAddr, ClearBreakAtIndex, ListBreaks, QuaBreakSet, SetBreakAtAbsAddr],
CirioDeltaFace USING[CallerInfo, GetCallersSPandPC],
CirioNubAccess USING[CreateSameWorldNub, DestroyNub, FileEntry, GetFileEntry, Handle, LookupSymEntryByName, LookupSymEntryByValue, LookupSymEntryByID, PCInfo, PCtoInfo, Read32BitsAsCard, SymEntry],
CirioTargets USING[Target],
CirioTypes USING[CC, CompilerContext, Node, Type],
Commander USING[CommandProc, Register],
IO USING[PutF1, PutFR1, rope, STREAM],
LoadStateAccess USING[CreateLoadStateHandle, GetLoadedModuleInfoFromAbsPC, LoadedModuleInfo, LoadStateHandle],
LocalCirio USING[BreakDest, nilBreakDest],
LocalCirioWorld USING[],
NewAmpersandProcs USING[Handle, HandleBody, InstallItems],
NewRMTW USING[CedarModuleSet, CreateCedarModuleSet, CreateRemoteMimosaTargetWorld, FlushUnknownFileCache, FlushUnknownSymbolCache, FlushUnknownTypeCodes, FrameNodeInfo, GetLoadedModuleInfo, GetNodeForCedarFrame, LoadedModuleInfo, RawFrameInfo, RemoteMimosaTargetWorld, ResetSearchPaths, ShowReportByLevel],
ObjectFiles USING[CreateParsed, GetLineNumForPC, GetPCForLineNum, Module, ModuleFromParsedAndPC, Parsed],
OneCasabaParser USING[ParserTable],
PFS USING [RopeFromPath, PathFromRope],
PFSNames USING [PATH, Equal],
RefTab,
Rope USING[Cat, Equal, Substr, ROPE],
RopeHash USING[FromRope],
SourceFileOps USING [OpenSource, Position],
StackCirio USING[OpenDummyStack, OpenStack, ResetStack, Stack],
SystemInterface USING [ShowReport, FileSet, CirioFile, CloseFileSet, CreateFileSet, GetCirioFile];
LocalCirioImpl:
CEDAR
MONITOR
LOCKS connection USING connection: Connection
IMPORTS AmpersandContext, BasicTime, CCTypes, CedarCode, CirioBackstop, CirioBreakAccess, CirioDeltaFace, CirioNubAccess, Commander, IO, LoadStateAccess, NewAmpersandProcs, NewRMTW, ObjectFiles, PFS, PFSNames, RefTab, Rope, RopeHash, SourceFileOps, StackCirio, SystemInterface
EXPORTS LocalCirio, LocalCirioWorld =
BreakDest: TYPE = LocalCirio.BreakDest;
nilBreakDest: BreakDest = LocalCirio.nilBreakDest;
ConnectionList: TYPE ~ LIST OF Connection;
Connection: TYPE = REF ConnectionBody;
ConnectionBody:
PUBLIC
TYPE =
MONITORED
RECORD[
open: BOOLEAN,
forRemote: BOOLEAN, -- true if created to provide local ampersand vars for a remoteCirio
searchDirectories: REF LIST OF PFSNames.PATH,
searchDirectoryLock: Connection,
tsOut: IO.STREAM, -- WARNING: this field is very transient. It is only valid during an interpretation of an expression, and was placed here for the convenience of ampersand routines and (local target wrld) user routines called through the interpreter.
aph: NewAmpersandProcs.Handle,
ampersandContext1: CirioTypes.Node,
ampersandContext2: CirioTypes.Node,
cc: CC,
breakDest: BreakDest,
rmtw: NewRMTW.RemoteMimosaTargetWorld,
cedarModules: NewRMTW.CedarModuleSet,
nub: CirioNubAccess.Handle,
target: CirioTargets.Target,
breaks: CirioBreakAccess.CirioBreakSet,
fileSet: SystemInterface.FileSet,
lsh: LoadStateAccess.LoadStateHandle,
cParserTable: OneCasabaParser.ParserTable,
dbxActive: BOOLEAN ¬ FALSE];
Connections
thisWorldLock: Connection ¬
NEW[ConnectionBody];
serves as a monitor lock for the following
commonFileSet: SystemInterface.FileSet ¬ NIL;
commonCedarModules: NewRMTW.CedarModuleSet ¬ NIL;
commonNub: CirioNubAccess.Handle ¬ NIL;
commonTarget: CirioTargets.Target ¬ NIL;
commonBreaks: RefTab.Ref--BreakDest -> CirioBreakAccess.CirioBreakSet-- ¬ RefTab.Create[equal: BDEqual, hash: BDHash];
commonlsh: LoadStateAccess.LoadStateHandle ¬ NIL;
commonSearchDirectories: REF LIST OF PFSNames.PATH ¬ NIL;
commonSearchDirectoryLock: Connection ¬ NIL;
availConnections: RefTab.Ref--BreakDest -> ConnectionList-- ¬ RefTab.Create[equal: BDEqual, hash: BDHash];
Note: we delay creating any worlds until all modules have been started, because the nominal creation code will be calling procedures in those modules.
There are more than one world so that we can have multiple independent cirios active at one time, e.g. if an error is raised during an interpreted procedure call, while at the same time avoiding monitor deadlocks.
However, they will all share common CedarModuleSet, CirioNubAccess.Handle, CirioBreakAccess.CirioBreakSet (per break dest), SystemInterface.FileSet, and LoadStateAccess.LoadStateHandle. I assume these modules will suitably protect themselves, and that none of them will be holding a monitor lock during an interpreted procedure call.
RecreateThisWorldCirioConnection: Commander.CommandProc =
BEGIN
inner: ENTRY PROC[connection: Connection] = {InstallNewConnectionComponents[cmd.out]};
inner[thisWorldLock];
END;
"thisWorldLock" must be held during a call to this procedure
InstallNewConnectionComponents:
PROC[reports:
IO.
STREAM] =
BEGIN
ENABLE
UNWIND => {
commonFileSet ¬ NIL;
commonCedarModules ¬ NIL;
commonCedarModules ¬ NIL;
commonBreaks ¬ RefTab.Create[equal: BDEqual, hash: BDHash];
commonlsh ¬ NIL;
commonSearchDirectories ¬ NIL;
commonSearchDirectoryLock ¬ NIL};
IF commonNub # NIL THEN CirioNubAccess.DestroyNub[commonNub];
IF commonFileSet # NIL THEN SystemInterface.CloseFileSet[commonFileSet];
commonFileSet ¬ SystemInterface.CreateFileSet[];
commonCedarModules ¬ NewRMTW.CreateCedarModuleSet[commonFileSet];
commonNub ¬ CirioNubAccess.CreateSameWorldNub[];
commonTarget ← CirioTargets.CreateTarget[commonNub];
commonTarget ¬ NARROW[commonNub.target];
commonBreaks.Erase[];
commonlsh ¬ LoadStateAccess.CreateLoadStateHandle["sameWorld", commonNub, commonFileSet];
commonSearchDirectories ¬ NEW[LIST OF PFSNames.PATH ¬ NIL];
commonSearchDirectoryLock ¬ NEW[ConnectionBody];
availConnections.Erase[];
END;
connection param must be "thisWorldLock"
TryForExistingConnection:
ENTRY
PROC[connection: Connection, breakDest: BreakDest]
RETURNS[Connection] =
BEGIN
rbd: REF BreakDest ~ NEW [BreakDest ¬ breakDest];
acl: ConnectionList ~ NARROW[availConnections.Fetch[rbd].val];
IF acl#
NIL
THEN {
first: Connection ~ acl.first;
IF first.open THEN RETURN WITH ERROR CCE[cirioError, "Locking failure for a local connection"];
first.open ¬ TRUE;
[] ¬ availConnections.Store[rbd, acl.rest];
RETURN [first]}
ELSE RETURN[NIL];
END;
BuildCommon:
PROC[cc:
CC, breakDest: BreakDest, reports:
IO.
STREAM, setCTC:
BOOL, wdirs:
LIST
OF
ROPE]
RETURNS[Connection] =
BEGIN
connection param must be "thisWorldLock"
designed not to do anything dangerous while the lock is held
simply collects common stuff into some records
makeProtoConnection:
ENTRY
PROC[connection: Connection]
RETURNS[Connection] =
BEGIN
rbd: REF BreakDest ~ NEW [BreakDest ¬ breakDest];
bs: CirioBreakAccess.CirioBreakSet;
IF commonFileSet = NIL THEN InstallNewConnectionComponents[reports];
IF (bs ¬ CirioBreakAccess.QuaBreakSet[commonBreaks.Fetch[rbd].val].it) =
NIL
THEN {
bs ¬ CirioBreakAccess.CreateCirioBreakSet[commonNub, breakDest.fileNameStem, breakDest.breakProcName];
[] ¬ commonBreaks.Store[rbd, bs]};
BEGIN
aph: NewAmpersandProcs.Handle ¬
NEW[NewAmpersandProcs.HandleBody¬[
out: NIL, -- only valid during a text line interpretation in StackCirio
rmtw: NIL,
cedarModules: commonCedarModules,
nub: commonNub,
target: commonTarget,
fileSet: commonFileSet,
lsh: commonlsh]];
pc: Connection ¬
NEW[ConnectionBody¬[
open: TRUE,
forRemote: FALSE,
searchDirectories: commonSearchDirectories,
searchDirectoryLock: commonSearchDirectoryLock,
aph: aph,
ampersandContext1: NIL,
ampersandContext2: NIL,
cc: cc,
breakDest: breakDest,
rmtw: NIL,
cedarModules: commonCedarModules,
nub: commonNub,
target: commonTarget,
breaks: bs,
fileSet: commonFileSet,
lsh: commonlsh,
cParserTable: NIL]];
RETURN[pc]
END;
END;
pc: Connection ¬ makeProtoConnection[thisWorldLock];
lctw: CCTypes.LocalCedarTargetWorld ¬
NEW[CCTypes.LocalCedarTargetWorldBody¬[
createNodeFromRefAny: NIL,
createFrameNodeForSelf: LCTWCreateFrameNodeForSelf,
data: pc]];
Add the directories in REVERSE ORDER because AddDir adds to the front of the list!!
AddDir[pc, "[PCedar2.0]<Cirio>", reports];
AddDir[pc, "[PCedar2.0]<CirioThings>", reports];
AddDir[pc, "[PCedar2.0]<Atom>", reports];
AddDir[pc, "[PCedar2.0]<Rope>", reports];
AddDir[pc, "-compiled:/CirioCompiledData", reports];
We include these directories so that examination of "navel" will procede correctly for a released Cirio. This is done before CreateRemoteMimosaTargetWorld so that the studying of CirioRopeHelper done therein will succeed on first try. The following files are needed (on August 17, 1991):
CirioThings/CirioRopeHelper.mob
Cirio/CCTypesImpl.mob
Cirio/CirioTypes.mob
Cirio/NewAmpersandProcs.mob
Cirio/NewAmpersandProcsImpl.mob
Rope/Rope.mob
Atom/AtomPrivate.mob
EnsureDirs[pc, wdirs, reports];
pc.ampersandContext1 ¬ AmpersandContext.CreateAnAmpersandContext[cc];
pc.ampersandContext2 ¬ AmpersandContext.CreateAnAmpersandContext[cc];
pc.rmtw ¬ NewRMTW.CreateRemoteMimosaTargetWorld["sameWorld", pc.nub, cc, pc.cedarModules, pc.lsh, reports, setCTC];
pc.aph.rmtw ¬ pc.rmtw;
CCTypes.RegisterLocalCedarTargetWorld[lctw, pc.cc];
all local connections register themselves with their cc
BUT, outside the monitor lock
RETURN[pc];
END;
GetConnection:
PUBLIC
PROC[breakDest: BreakDest, reports:
IO.
STREAM, workingDirectories:
LIST
OF
ROPE]
RETURNS[Connection] = {
ENABLE SystemInterface.ShowReport =>
{NewRMTW.ShowReportByLevel[reports, msgText, priority];
IO.PutF[reports, "%g\N", IO.rope[msgText]];
RESUME};
note: connection argument will be thisWorldLock
ans: Connection ¬ TryForExistingConnection[thisWorldLock, breakDest];
IF ans # NIL THEN EnsureDirs[ans, workingDirectories, reports]
ELSE {
cc: CC ¬ CCTypes.CreateCedarCompilerContext[];
ans ¬ BuildCommon[cc, breakDest, reports, TRUE, workingDirectories];
NewAmpersandProcs.InstallItems[ans.ampersandContext2, ans.aph, ans.cc];
};
RETURN [ans]};
EnsureDirs:
PROC [c: Connection, wdirs:
LIST
OF
ROPE, reports:
IO.
STREAM] ~ {
IF wdirs#
NIL
THEN {
EnsureDirs[c, wdirs.rest, reports];
AddDir[c, wdirs.first, reports, FALSE]};
RETURN};
ExtractCcFromConnection:
PUBLIC
PROC [c: Connection]
RETURNS [CirioTypes.
CC]
~ {RETURN [c.cc]};
this procedure is exported to LocalCirioWorld, and is called by RemoteCirioImpl to permit construction of ampersand routines.
parallels GetConnection, except that registration is with supplied cc, we always create a connection, we let the caller install the ampersand procs, and breakpoints cannot be set through this connection.
CreateAndRegisterNominalLocalCirioTW:
PUBLIC
PROC[cc: CCTypes.
CC, reports:
IO.
STREAM] =
BEGIN
ENABLE SystemInterface.ShowReport =>
{NewRMTW.ShowReportByLevel[reports, msgText, priority];
IO.PutF[reports, "%g\N", IO.rope[msgText]];
RESUME};
connection: Connection ¬ BuildCommon[cc, nilBreakDest, reports, FALSE, NIL];
connection.forRemote ¬ TRUE;
END;
in this case, "self" is the caller of this procedure
This procedure duplicates assorted activity in StackCirioImpl
LCTWCreateFrameNodeForSelf:
PROC[lctw: CCTypes.LocalCedarTargetWorld, cc: CCTypes.
CC]
RETURNS[CirioTypes.Node] =
BEGIN
connection: Connection ¬ NARROW[lctw.data];
ourInfo: CirioDeltaFace.CallerInfo ¬ CirioDeltaFace.GetCallersSPandPC[connection.nub];
note: In CirioDeltaFace.GetCallersSPandPC, "caller" refers to the caller of CirioDeltaFace.GetCallersSPandPC, i.e., ourselves. In LCTWCreateFrameNodeForSelf, "self" refers to the caller of LCTWCreateFrameNodeForSelf, i.e., our caller.
note: in the following var names, "caller" refers to the same frame as "Self" in our procedure name, that is, our caller.
ourSP:
CARD ¬ ourInfo.callersStackPointer;
the nomenclature is such that ourInfo.callersStackPointer is really our stack pointer.
callerPC: CARD ¬ CirioNubAccess.Read32BitsAsCard[[connection.nub, ourSP+(15*4), 0, FALSE, TRUE]];
callerLedo: REF LSA.LoadedModuleInfo ¬ LSA.GetLoadedModuleInfoFromAbsPC[connection.lsh, callerPC];
callerLoadedCedarModule: REF NewRMTW.LoadedModuleInfo ¬ NewRMTW.GetLoadedModuleInfo[connection.cedarModules, callerLedo];
ourFP:
CARD ¬ CirioNubAccess.Read32BitsAsCard[[connection.nub, ourSP+(14*4), 0,
FALSE,
TRUE]];
This constant (14*4) exists in several places. They should be combined.
callerSP: CARD ¬ ourFP;
callerFP:
CARD ¬ CirioNubAccess.Read32BitsAsCard[[connection.nub, callerSP+(14*4), 0,
FALSE,
TRUE]];
This constant (14*4) exists in several places. They should be combined.
callerRawFrameInfo:
REF NewRMTW.RawFrameInfo ¬
NEW[NewRMTW.RawFrameInfo ¬ [
callerPC,
callerFP,
callerSP]];
callerInfo: REF NewRMTW.FrameNodeInfo;
IF callerLoadedCedarModule=NIL THEN CCE[cirioError, "Cirio can't NewRMTW.GetLoadedModuleInfo for itself"];
callerInfo ¬ NewRMTW.GetNodeForCedarFrame[connection.rmtw, callerLoadedCedarModule, callerRawFrameInfo];
RETURN[callerInfo.node];
END;
FlushUnknownFileCache:
PUBLIC
ENTRY
PROC[connection: Connection, reports:
IO.
STREAM] =
BEGIN
ENABLE UNWIND => NULL;
IF NOT connection.open THEN RETURN;
NewRMTW.FlushUnknownFileCache[connection.cedarModules, BasicTime.Now[]];
NewRMTW.FlushUnknownSymbolCache[connection.rmtw, BasicTime.Now[], reports];
NewRMTW.FlushUnknownTypeCodes[connection.rmtw];
END;
ReleaseConnection:
PUBLIC
ENTRY
PROC[connection: Connection, reports:
IO.
STREAM] =
BEGIN ENABLE UNWIND => NULL;
renamed: Connection ¬ connection;
to be visible inside putBack
putBack has to reuse the identifier: connection so as to be able to lock
PutBack:
PROC[connection: Connection] = {
ENABLE UNWIND => NULL;
rbd: REF BreakDest ~ NEW [BreakDest ¬ renamed.breakDest];
acl: ConnectionList ¬ NARROW[availConnections.Fetch[rbd].val];
acl ¬ CONS[renamed, acl];
[] ¬ availConnections.Store[rbd, acl];
RETURN};
IF NOT connection.open THEN RETURN WITH ERROR CCE[cirioError, "some fool released a local connection that wasn't open"];
connection.open ¬ FALSE;
IF NOT connection.forRemote THEN PutBack[thisWorldLock];
RETURN; END;
DoUnderMonitorLock:
PUBLIC
ENTRY
PROC[connection: Connection, toDo:
PROC] =
BEGIN
ENABLE UNWIND => NULL;
toDo[];
END;
symbols
these procedures are expected to become ampersand procedures. During the interpreted call on them the connection will be locked, so there is no need to lock it here. In fact, that would cause a monitor deadlock.
LookupSym:
PROC[h: Connection, name:
ROPE, numToSkip:
INT ¬ 0, externOnly:
BOOL ¬
TRUE]
RETURNS[CirioNubAccess.SymEntry] =
{RETURN[CirioNubAccess.LookupSymEntryByName[h.nub, name, FALSE, externOnly, numToSkip]]};
LookupAddr:
PROC[h: Connection, val:
CARD, numToSkip:
INT ¬ 0]
RETURNS[CirioNubAccess.SymEntry] =
{RETURN[CirioNubAccess.LookupSymEntryByValue[h.nub, val, numToSkip]]};
LookupID:
PROC[h: Connection, symID:
CARD]
RETURNS[CirioNubAccess.SymEntry] =
{RETURN[CirioNubAccess.LookupSymEntryByID[h.nub, symID]]};
LookupFile:
PROC[h: Connection, seqNum:
CARD]
RETURNS[entry: CirioNubAccess.FileEntry] =
{RETURN[CirioNubAccess.GetFileEntry[h.nub, seqNum]]};
GetPCInfo:
PROC[h: Connection, absPC:
CARD]
RETURNS[CirioNubAccess.PCInfo] =
{RETURN[CirioNubAccess.PCtoInfo[h.nub, absPC]]};
misc
DebugOn:
PROC =
BEGIN
DebugFlag ¬ TRUE;
END;
DebugOff:
PROC =
BEGIN
DebugFlag ¬ FALSE;
END;
GetRelPCForCLine:
PROC[dotOName: PFSNames.
PATH, cLineNum:
CARD, h: Connection]
RETURNS[
CARD] =
BEGIN
file: SystemInterface.CirioFile ¬ SystemInterface.GetCirioFile[h.fileSet, dotOName];
container: ObjF.Parsed ¬ ObjF.CreateParsed[file];
AcquireModule:
PROC
RETURNS[ObjF.Module] =
BEGIN
stabRange ← ObjF.AlternativeFindModuleStabRange[container, 1];
RETURN[ObjF.ModuleFromParsedAndPC[container, [[0, ""], 1]]];
END;
dotO: ObjF.Module ¬ AcquireModule[];
relPC: CARD ¬ ObjF.GetPCForLineNum[dotO, cLineNum].relPC;
RETURN[relPC];
END;
GetCLineForRelPC:
PROC[dotOName: PFSNames.
PATH, relPC:
CARD, h: Connection]
RETURNS[
CARD] =
BEGIN
file: SystemInterface.CirioFile ¬ SystemInterface.GetCirioFile[h.fileSet, dotOName];
container: ObjF.Parsed ¬ ObjF.CreateParsed[file];
AcquireModule:
PROC
RETURNS[ObjF.Module] =
BEGIN
stabRange ← ObjF.AlternativeFindModuleStabRange[container, 1];
RETURN[ObjF.ModuleFromParsedAndPC[container, [[0, ""], 1]]];
END;
dotO: ObjF.Module ¬ AcquireModule[];
cLine: CARD ¬ ObjF.GetLineNumForPC[dotO, [[0, ""], relPC]];
RETURN[cLine];
END;
BDEqual:
PROC [key1, key2:
REF
ANY]
RETURNS [
BOOL] ~ {
bd1: REF BreakDest ~ NARROW[key1];
bd2: REF BreakDest ~ NARROW[key2];
RETURN [bd1.fileNameStem.Equal[bd2.fileNameStem] AND bd1.breakProcName.Equal[bd2.breakProcName]]};
BDHash:
PROC [key:
REF
ANY]
RETURNS [
CARDINAL] ~ {
bd: REF BreakDest ~ NARROW[key];
RETURN [RopeHash.FromRope[bd.fileNameStem] + RopeHash.FromRope[bd.breakProcName]]};