-- PcCold.mesa last edit, Bruce October 9, 1980 4:08 PM
DIRECTORY
Copier USING [CopyExternalBody, Outer],
DebugFormat USING [EXOI],
DI USING [CTXIndex, MapCtx],
DSyms USING [GFHandle, GFrameMdi],
Frames USING [Invalid],
Gf USING [FrameGfi, GFI],
MachineDefs USING [FHandle, GFHandle, MaxParmsInStack, WordLength],
Pc USING [
Bti, BytePC, CacheCBti, CtxItem, CtxLink, EpToCBti, EVRange, GetPc, NullPC, Reason],
PcOps USING [
BytePC, cache, CacheLimit, FindUserCbti, Free, Head, Item, ItemNull, ItemObject],
PrincOps USING [BytePC, ControlLink, EPIndex],
Storage USING [Node],
Symbols USING [
bodyType, BTIndex, BTNull, CBTIndex, CBTNull, ContextLevel, CTXIndex, CTXNull,
ISEIndex, ISENull, MDIndex, RecordSEIndex, RecordSENull, RootBti, seType],
SymbolTable USING [Base, Missing],
Table USING [Base, Bounds];
PcCold: PROGRAM
IMPORTS Copier, DI, DSyms, Frames, Gf, Pc, PcOps,
Storage, SymbolTable, Table
EXPORTS Pc, PcOps =
BEGIN OPEN PcOps, PrincOps, MachineDefs, Symbols;
NotInAnyProcedure: PUBLIC SIGNAL = CODE;
CantCacheInlines: ERROR = CODE;
NotCallable: ERROR = CODE;
NoBti: ERROR = CODE;
BadReason: ERROR = CODE;
FHandle: TYPE = MachineDefs.FHandle;
GFHandle: TYPE = MachineDefs.GFHandle;
EVRange: TYPE = Pc.EVRange;
FirstFree: PROC RETURNS [i: Item] =
BEGIN
i ← Free;
IF i = ItemNull THEN ERROR;
Free ← cache[i].link;
END;
ResetCache: PUBLIC PROCEDURE =
BEGIN
i: Item;
Free ← Head ← ItemNull;
FOR i ← LOOPHOLE[0], i+SIZE[ItemObject] UNTIL
LOOPHOLE[i,CARDINAL] >= CacheLimit DO
cache[i].link ← Free; Free ← i;
ENDLOOP;
END;
EVSize: PUBLIC PROC [mdi: MDIndex] RETURNS [max: EVRange] =
BEGIN
FindMax: PROC [base: SymbolTable.Base] =
BEGIN
GetMax: PROC [bti: BTIndex] RETURNS [stop: BOOLEAN] =
BEGIN
WITH base.bb[bti] SELECT FROM
Callable => IF ~inline THEN max ← MAX[max,entryIndex];
ENDCASE;
RETURN[FALSE]
END;
[] ← base.EnumerateBodies[Symbols.RootBti, GetMax];
END;
max ← 0;
Copier.Outer[mdi,FindMax];
END;
Card: PROC [BytePC] RETURNS [CARDINAL] = MACHINE CODE BEGIN END;
GetEp: PROC [pc: BytePC, gf: GFHandle, mdi: MDIndex]
RETURNS [ep: EVRange, start: BytePC] =
BEGIN
i, maxEp: EVRange;
diff: CARDINAL ← LAST[CARDINAL];
anyProcedure: BOOLEAN ← FALSE;
last: BytePC;
maxEp ← EVSize[mdi];
FOR i IN [0..maxEp] DO
last ← Pc.GetPc[gf,i];
IF Card[last] > Card[pc] THEN LOOP;
IF Card[pc] - Card[last] > diff THEN LOOP;
diff ← Card[pc] - Card[last];
ep ← i; start ← last;
anyProcedure ← TRUE;
ENDLOOP;
IF ~anyProcedure THEN SIGNAL NotInAnyProcedure;
RETURN;
END;
EpCold: PUBLIC PROC [pc: BytePC, gf: GFHandle]
RETURNS [ep: EVRange, start: BytePC] =
BEGIN
mdi: MDIndex = DSyms.GFrameMdi[gf];
[ep, start] ← GetEp[pc,gf,mdi];
CheckPc[pc,ConvertEp[ep,start,gf,mdi]];
END;
CheckPc: PROC [pc: BytePC, i: Item] = {
IF LOOPHOLE[pc,CARDINAL] >= LOOPHOLE[cache[i].start,CARDINAL] AND
LOOPHOLE[pc,CARDINAL] <= LOOPHOLE[cache[i].end,CARDINAL] THEN RETURN;
SIGNAL NotInAnyProcedure};
EpToCBtiCold: PUBLIC PROC [ep: EVRange, gf: GFHandle, start: BytePC]
RETURNS [cbti: CBTIndex] =
BEGIN
cbti ← cache[ConvertEp[ep,start,gf,DSyms.GFrameMdi[gf !
Frames.Invalid, SymbolTable.Missing => GOTO exit]]].dCbti;
EXITS
exit => RETURN [CBTNull]
END;
CacheCBtiCold: PUBLIC PROC [mdi: MDIndex, gf: GFHandle, cbti: CBTIndex]
RETURNS [dCbti: CBTIndex] =
BEGIN
initialPc: BytePC;
ep: EVRange;
i: Item;
FillInEp: PROC [base: SymbolTable.Base] = {ep ← base.bb[cbti].entryIndex};
Copier.Outer[mdi,FillInEp];
initialPc ← Pc.GetPc[gf,ep];
i ← CacheIt[cbti,ep,initialPc,gf,mdi];
dCbti ← cache[i].dCbti;
END;
CacheIt: PROC [cbti: CBTIndex,
ep: EVRange, start: BytePC, gf: GFHandle, mdi: MDIndex]
RETURNS [i: Item] =
BEGIN
CheckInline: PROC [base: SymbolTable.Base] =
{IF base.bb[cbti].inline THEN ERROR CantCacheInlines};
FillInFromTable: PROC [base: SymbolTable.Base] =
BEGIN
cache[i].hasSons ← base.bb[cbti].firstSon # BTNull;
WITH base.bb[cbti].info SELECT FROM
External => cache[i].end ← [(start+bytes-1)];
ENDCASE => ERROR;
WITH base.bb[cbti] SELECT FROM
Inner => cache[i].inner ← TRUE;
ENDCASE;
END;
Copier.Outer[mdi,CheckInline];
i ← FirstFree[];
cache[i] ← [link: Head, ep: ep, gf: gf, start: start, userCbti: cbti,
end:, dCbti:, hasSons:, inner: FALSE];
Head ← i;
Copier.Outer[mdi,FillInFromTable];
cache[i].dCbti ← Copier.CopyExternalBody[mdi,cbti];
END;
FindBtiWithEp: PROC [ep: Pc.EVRange, mdi: MDIndex] RETURNS [bti: BTIndex] =
BEGIN
Find: PROC [base: SymbolTable.Base] =
BEGIN
SearchForEp: PROC [bti: BTIndex] RETURNS [BOOLEAN] =
BEGIN
WITH base.bb[bti] SELECT FROM
Callable => RETURN[~inline AND ep = entryIndex];
ENDCASE => RETURN[FALSE]
END;
bti ← base.EnumerateBodies[Symbols.RootBti, SearchForEp];
END;
Copier.Outer[mdi,Find];
IF bti = BTNull THEN ERROR NoBti;
END;
ConvertEp: PROC [
ep: EVRange, start: BytePC, gf: GFHandle, mdi: MDIndex]
RETURNS [i: Item] =
BEGIN
bti: BTIndex ← FindBtiWithEp[ep,mdi];
IF start = Pc.NullPC THEN start ← Pc.GetPc[gf,ep];
i ← CacheIt[LOOPHOLE[bti],ep,start,gf,mdi];
END;
LinkToCbti: PUBLIC PROC [pd: PrincOps.ControlLink] RETURNS [cbti: CBTIndex]=
BEGIN
EntryPoint: TYPE = RECORD [SELECT OVERLAID * FROM
detail => [gfi: [0..4), ep: PrincOps.EPIndex],
index => [i: EVRange],
ENDCASE];
ep: EntryPoint;
gf: GFHandle ← Gf.FrameGfi[pd.gfi];
ep.ep ← pd.ep; ep.gfi ← pd.gfi - Gf.GFI[gf];
cbti ← Pc.EpToCBti[LOOPHOLE[ep], gf
! CantCacheInlines => {cbti ← Symbols.CBTNull; CONTINUE}];
END;
LinkToIsei: PUBLIC PROC [pd: PrincOps.ControlLink] RETURNS [Symbols.ISEIndex]=
BEGIN
cbti: CBTIndex ← LinkToCbti[pd];
IF cbti = CBTNull THEN RETURN[Symbols.ISENull];
RETURN[Table.Bounds[bodyType].base[cbti].id];
END;
ParentCbtiCold: PUBLIC PROC [pc: BytePC, gf: GFHandle, mdi: MDIndex] RETURNS [i: Item] =
BEGIN
ep: EVRange;
start: BytePC;
[ep, start] ← GetEp[pc,gf,mdi];
i ← ConvertEp[ep,start,gf,mdi];
CheckPc[pc,i];
END;
ConvertCbti: PUBLIC PROC [
lastBti: BTIndex, pc, start: BytePC, base: SymbolTable.Base]
RETURNS [bti: BTIndex] =
BEGIN
bodyStart: BytePC;
bti ← lastBti;
DO
FOR lastBti ← base.SonBti[bti], base.SiblingBti[lastBti]
UNTIL lastBti = BTNull DO
WITH body: base.bb[lastBti] SELECT FROM
Callable => LOOP;
Other =>
BEGIN
bodyStart ← [start + body.relOffset];
WITH body.info SELECT FROM
External => IF pc IN [bodyStart..bodyStart+bytes) THEN
BEGIN bti ← lastBti; EXIT END;
ENDCASE;
END;
ENDCASE;
REPEAT
FINISHED => RETURN
ENDLOOP;
ENDLOOP;
END;
argGf: GFHandle;
ContextList: PUBLIC PROC [
pc: BytePC, gf: GFHandle, reason: Pc.Reason, exoi: DebugFormat.EXOI ← in]
RETURNS [Pc.CtxLink] =
BEGIN
bti: BTIndex ← Pc.Bti[pc,gf];
list: Pc.CtxLink;
mdi: Symbols.MDIndex ← DSyms.GFrameMdi[gf];
Base: PROC [iBase: SymbolTable.Base] = {list ← Walk[bti,iBase,reason,exoi]};
argGf ← gf;
CollectCbtis[mdi,bti];
Copier.Outer[mdi,Base];
FOR i: Pc.CtxLink ← list, i.link UNTIL i = NIL DO
IF ~i.mapped THEN i.ictx ← DI.MapCtx[mdi,i.ictx];
ENDLOOP;
SELECT reason FROM
search => RETURN[list];
print => RETURN[Reverse[list]];
ENDCASE => ERROR BadReason;
END;
CollectCbtis: PROC [mdi: Symbols.MDIndex, bti: BTIndex] = {
list: ARRAY Symbols.ContextLevel OF CBTIndex ← ALL[Symbols.CBTNull];
length: Symbols.ContextLevel ← 0;
Collect: PROC [iBase: SymbolTable.Base] = {
FOR ibti: BTIndex ← bti, iBase.ParentBti[ibti] UNTIL ibti = Symbols.BTNull DO
WITH iBase.bb[ibti] SELECT FROM
Callable => {list[length] ← LOOPHOLE[ibti]; length ← length + 1};
ENDCASE;
IF bti = Symbols.RootBti THEN EXIT;
ENDLOOP};
Copier.Outer[mdi,Collect];
FOR i: Symbols.ContextLevel IN [0..length) DO
[] ← Pc.CacheCBti[mdi,argGf,list[i]];
ENDLOOP};
Walk: PROC [
bti: Symbols.BTIndex, base: SymbolTable.Base, why: Pc.Reason, ex: DebugFormat.EXOI]
RETURNS [list: Pc.CtxLink] =
BEGIN
ibti: Symbols.BTIndex;
indent: CARDINAL ← 0;
list ← NIL;
FOR ibti ← bti, base.ParentBti[ibti] UNTIL ibti = Symbols.BTNull DO
indent ← indent + 2;
WITH base.bb[ibti] SELECT FROM
Callable => IF why = print THEN EXIT;
ENDCASE;
IF ibti = Symbols.RootBti THEN EXIT;
ENDLOOP;
FOR ibti ← bti, base.ParentBti[ibti] UNTIL ibti = Symbols.BTNull DO
WITH body: base.bb[ibti] SELECT FROM
Callable =>
BEGIN
list ← AddToList[list, body.localCtx, indent, body.level];
IF why = print THEN RETURN;
list ← AddArguments[list,ibti,ex];
ex ← in;
END;
ENDCASE => list ← AddToList[list, body.localCtx, indent, body.level];
indent ← indent - 2;
IF ibti = Symbols.RootBti THEN RETURN;
ENDLOOP;
END;
AddToList: PROC [
list: Pc.CtxLink, ctx: Symbols.CTXIndex, indent: CARDINAL, level: Symbols.ContextLevel]
RETURNS [newList: Pc.CtxLink] =
BEGIN
null: BOOLEAN ← ctx = Symbols.CTXNull;
newList ← Storage.Node[SIZE[Pc.CtxItem]];
IF null THEN
newList↑ ← [
link: list, indirect: FALSE, indent: indent, onStack: FALSE,
mapped: null, null: null, body: empty[level]]
ELSE newList↑ ← [
link: list, indirect: FALSE, indent: indent, onStack: FALSE,
mapped: null, null: null, body: context[ctx]];
END;
AddArguments: PROC [list: Pc.CtxLink, bti: BTIndex, ex: DebugFormat.EXOI]
RETURNS [newList: Pc.CtxLink] =
BEGIN
i: Item = FindUserCbti[argGf, LOOPHOLE[bti]];
seb: Table.Base = Table.Bounds[Symbols.seType].base;
bb: Table.Base = Table.Bounds[Symbols.bodyType].base;
cbti: CBTIndex;
IF i = ItemNull THEN ERROR NotCallable;
cbti ← cache[i].dCbti;
WITH seb[bb[cache[i].dCbti].ioType] SELECT FROM
transfer => {
newList ← AddRecord[seb, list, LOOPHOLE[outRecord], ex = exit];
newList ← AddRecord[seb, newList, LOOPHOLE[inRecord], ex = entry] };
ENDCASE => ERROR NotCallable;
END;
AddRecord: PROC [
seb: Table.Base, list: Pc.CtxLink, rsei: Symbols.RecordSEIndex, onStack: BOOLEAN]
RETURNS [newList: Pc.CtxLink] =
BEGIN
IF rsei = Symbols.RecordSENull THEN RETURN [list];
newList ← Storage.Node[SIZE[Pc.CtxItem]];
newList↑ ← [link: list, indent:, onStack: onStack, mapped: TRUE, null: FALSE,
indirect: seb[rsei].length/MachineDefs.WordLength > MaxParmsInStack,
body: context[seb[rsei].fieldCtx]];
END;
Reverse: PROC [list: Pc.CtxLink] RETURNS [reverse: Pc.CtxLink] =
BEGIN
next: Pc.CtxLink;
reverse ← NIL;
FOR i: Pc.CtxLink ← list, next UNTIL i = NIL DO
next ← i.link;
i.link ← reverse;
reverse ← i;
ENDLOOP;
END;
END.