-- FramesHot.mesa last edit, Bruce September 22, 1980 5:47 PM
DIRECTORY
DebugOps USING [GFHandle, ReadCodeByte, ShortCopyREAD, ShortREAD, UserAborted],
DOutput USING [Line, Octal],
Frames USING [LG],
Gf USING [],
Inline USING [DIVMOD],
Lf USING [],
MachineDefs USING [
BytePC, ControlLink, FHandle, Frame, GFHandle, GfiToFrame, GfiToOffset, GFTIndex,
GlobalFrame, NullGF, NullOffset, RealToBytePC, TypeOfLink],
Mopcodes USING [zBRK, zNOOP],
PrincOps USING [ControlLink, EPIndex, EPRange, FrameCodeBase, ProcDesc],
State USING [GetGS, GSHandle],
Storage USING [Free, Node],
UserInput USING [userAbort];
FramesHot: PROGRAM
IMPORTS DebugOps, DOutput, Inline, MachineDefs, State, Storage, UserInput
EXPORTS Frames, Gf, Lf =
BEGIN OPEN MachineDefs;
NoPrevious: PUBLIC SIGNAL [f: FHandle] = CODE;
Invalid: PUBLIC SIGNAL [f: POINTER] = CODE;
Clobbered: PUBLIC SIGNAL [f: FHandle] = CODE;
NoAccessLink: PUBLIC SIGNAL [f: FHandle] = CODE;
FramePointer: TYPE = MACHINE DEPENDENT RECORD [SELECT OVERLAID * FROM
pointer => [fill: [0..77777B], lg: Frames.LG],
link => [cl: PrincOps.ControlLink],
fullPointer => [frame: POINTER],
ENDCASE];
Item: TYPE = POINTER TO ItemObject;
ItemObject: TYPE = MACHINE DEPENDENT RECORD [
link: Item,
fp: FramePointer,
frame: SELECT OVERLAID * FROM
global => [globalFrame: GlobalFrame],
local => [localFrame: local Frame],
ENDCASE];
data: State.GSHandle ← State.GetGS[];
Head: Item ← NIL;
Cache: PUBLIC PROC [f: POINTER, lg: Frames.LG] RETURNS [copy: POINTER] =
BEGIN
p,last: Item;
fp: FramePointer;
IF f = NIL THEN ERROR Invalid[f];
FOR p ← Head, p.link UNTIL p = NIL DO
IF p.fp.lg = lg THEN
BEGIN
fp ← p.fp; fp.cl.tag ← FALSE; -- zero out tag
IF fp.frame = f THEN
BEGIN
copy ← @p.frame;
IF p = Head OR last = Head THEN RETURN;
last.link ← p.link; p.link ← Head; Head ← p;
RETURN;
END;
END;
last ← p;
ENDLOOP;
p ← Storage.Node[IF lg = global THEN SIZE[global ItemObject]
ELSE SIZE[local ItemObject]];
fp.cl ← LOOPHOLE[f,PrincOps.ControlLink];
IF fp.cl.tag THEN ERROR Invalid[f];
fp.lg ← lg;
copy ← @p.frame;
p↑ ← [link: Head, fp: fp, frame:];
Head ← p;
DebugOps.ShortCopyREAD[from: f, to: copy,
nwords: IF lg = global THEN SIZE[GlobalFrame] ELSE SIZE[local Frame]];
END;
FlushFrameCache: PUBLIC PROCEDURE =
BEGIN
p, next: Item;
FOR p ← Head, next UNTIL p = NIL DO
next ← p.link;
Storage.Free[p];
ENDLOOP;
Head ← NIL;
END;
Type: PUBLIC PROC [p: POINTER] RETURNS [Frames.LG] = {
RETURN[IF ValidateGF[p] THEN global ELSE local]};
CheckF: PUBLIC PROCEDURE [f: FHandle] =
BEGIN IF ~ValidateF[f] THEN SIGNAL Invalid[f] END;
ValidateF: PUBLIC PROCEDURE [f: FHandle] RETURNS [BOOLEAN] =
BEGIN
gf: GFHandle;
IF f = NIL THEN RETURN[FALSE];
IF (LOOPHOLE[f,CARDINAL] MOD 4) # 0 THEN RETURN[FALSE];
f ← Cache[f,local];
gf ← f.accesslink;
IF gf = MachineDefs.NullGF THEN RETURN[FALSE];
RETURN [ValidateGF[gf]];
END;
GF: PUBLIC PROCEDURE [f: FHandle] RETURNS [gf: GFHandle] =
BEGIN
CheckF[f];
f ← Cache[f,local];
gf ← f.accesslink;
IF gf = MachineDefs.NullGF THEN SIGNAL NoAccessLink[f];
CheckGF[gf];
END;
PC: PUBLIC PROCEDURE [f: FHandle] RETURNS [pc: BytePC] =
BEGIN
lf: FHandle ← Cache[f,local];
CheckF[f];
pc ← MachineDefs.RealToBytePC[LOOPHOLE[lf.pc]];
IF data.breakFrame = f THEN RETURN;
IF pc # 0 THEN
BEGIN OPEN Mopcodes, DebugOps;
IF ReadCodeByte[lf.accesslink,pc] # zBRK THEN pc ← [pc-1];
IF ReadCodeByte[lf.accesslink,pc] = zNOOP THEN pc ← [pc-1];
END;
END;
Previous: PUBLIC PROCEDURE [f: FHandle] RETURNS [prev: FHandle] =
BEGIN
link: MachineDefs.ControlLink;
CheckF[f];
f ← Cache[f,local];
IF UserInput.userAbort THEN SIGNAL DebugOps.UserAborted;
link ← LOOPHOLE[f.returnlink];
THROUGH [0..100] DO
SELECT MachineDefs.TypeOfLink[link] FROM
frame =>
IF link.frame = NIL THEN GOTO noPrev
ELSE IF ~ValidateF[link.frame] THEN GOTO clobbered
ELSE RETURN[link.frame];
procedure => GOTO noPrev;
indirect => link ← DebugOps.ShortREAD[LOOPHOLE[link]];
ENDCASE => GOTO clobbered;
REPEAT
noPrev => ERROR NoPrevious[f];
clobbered => ERROR Clobbered[f];
FINISHED => ERROR Clobbered[f];
ENDLOOP
END;
ValidateGF: PUBLIC PROC [gf: GFHandle] RETURNS [BOOLEAN] =
BEGIN
cl: PrincOps.ControlLink ← LOOPHOLE[gf];
gfi: MachineDefs.GFTIndex;
IF gf = NIL THEN RETURN[FALSE];
IF cl.proc OR cl.indirect THEN RETURN[FALSE];
gfi ← GFI[gf];
RETURN[MachineDefs.GfiToFrame[gfi] = gf]
END;
CheckGF: PUBLIC PROC[gf: GFHandle] =
BEGIN IF ~ValidateGF[gf] THEN SIGNAL Invalid[gf] END;
Copied: PUBLIC PROCEDURE [gf: GFHandle] RETURNS [BOOLEAN] =
BEGIN gf ← Cache[gf,global]; RETURN[gf.copied] END;
Started: PUBLIC PROCEDURE [gf: GFHandle] RETURNS [BOOLEAN] =
BEGIN gf ← Cache[gf,global]; RETURN[gf.started] END;
Shared: PUBLIC PROCEDURE [gf: GFHandle] RETURNS [BOOLEAN] =
BEGIN gf ← Cache[gf,global]; RETURN[gf.shared] END;
CheckStarted: PUBLIC PROC [gf: GFHandle] RETURNS [running: BOOLEAN] =
BEGIN
running ← Started[gf];
IF running THEN RETURN;
DOutput.Octal[gf]; DOutput.Line[" is not started!"L];
END;
GFI: PUBLIC PROCEDURE [gf: GFHandle] RETURNS [MachineDefs.GFTIndex] =
BEGIN gf ← Cache[gf,global]; RETURN[gf.gfi] END;
Links: PUBLIC PROCEDURE [gf: GFHandle] RETURNS [BOOLEAN] =
BEGIN gf ← Cache[gf,global]; RETURN[gf.codelinks] END;
CodeBase: PUBLIC PROC [gf: GFHandle] RETURNS [PrincOps.FrameCodeBase] =
BEGIN gf ← Cache[gf,global]; RETURN[gf.code] END;
Deleted: PUBLIC PROC [gfi: MachineDefs.GFTIndex] RETURNS [BOOLEAN] = {
RETURN[MachineDefs.GfiToFrame[gfi] = NullGF AND
MachineDefs.GfiToOffset[gfi] = MachineDefs.NullOffset]};
MakeDesc: PUBLIC PROC [gf: GFHandle, ep: CARDINAL] RETURNS [pd: PrincOps.ProcDesc] =
BEGIN
base: CARDINAL;
offset: PrincOps.EPIndex;
[base, offset] ← Inline.DIVMOD[ep, PrincOps.EPRange];
pd.gfi ← GFI[gf] + base;
pd.ep ← offset;
pd.tag ← TRUE;
END;
PreDeclared: PUBLIC PROC [u: UNSPECIFIED] RETURNS [BOOLEAN] =
BEGIN
Signals: ARRAY [0..4) OF INTEGER = [-1,1,3,5];
FOR i: CARDINAL IN [0..4) DO
IF u = Signals[i] THEN RETURN[TRUE]
ENDLOOP;
RETURN[FALSE]
END;
NewLink: PUBLIC PROC [ocl: ControlLink]
RETURNS [ncl: PrincOps.ControlLink] =
BEGIN
IF PreDeclared[ocl] THEN RETURN[LOOPHOLE[ocl]];
SELECT TypeOfLink[ocl] FROM
indirect, frame => ncl ← LOOPHOLE[ocl];
procedure => {ncl.gfi ← ocl.gfi; ncl.ep ← ocl.ep; ncl.tag ← TRUE};
ENDCASE => ncl ← LOOPHOLE[1];
END;
AddGfi: PUBLIC PROC [gf: GFHandle, cl: PrincOps.ControlLink]
RETURNS [pd: PrincOps.ProcDesc] = {
pd ← LOOPHOLE[cl]; pd.gfi ← pd.gfi + GFI[gf] - 1};
FrameGfi: PUBLIC PROC [gfi: GFTIndex] RETURNS [GFHandle] = {
RETURN[MachineDefs.GfiToFrame[gfi]]};
END.