-- PCPack.mesa last edit, Bruce June 10, 1980 10:03 PM DIRECTORY Copier: FROM "copier", DebugFormat: FROM "debugformat", DebugOps: FROM "debugops" USING [ReadCodeWord, ShortREAD], DI: FROM "di" USING [MapCtx], DSyms: FROM "dsyms", Frames: FROM "frames", Gf: FROM "gf", Lf: FROM "lf", Lookup: FROM "Lookup", MachineDefs: FROM "MachineDefs", Pc: FROM "pc", PrincOps: FROM "princops", SegmentDefs: FROM "segmentdefs", State: FROM "state", Storage: FROM "storage", StringDefs: FROM "stringdefs", Symbols: FROM "symbols", SymbolSegment: FROM "symbolsegment", SymbolTable: FROM "symboltable" USING [Base, Missing], Table: FROM "table"; PCPack: PROGRAM IMPORTS Copier, DebugOps, DI, DSyms, Frames, Gf, Lf, Pc, SegmentDefs, State, Storage, SymbolTable, Table EXPORTS Pc = BEGIN OPEN PrincOps, Symbols; CantCacheInlines: ERROR = CODE; NotCallable: ERROR = CODE; NoBti: ERROR = CODE; FHandle: TYPE = MachineDefs.FHandle; GFHandle: TYPE = MachineDefs.GFHandle; EVRange: TYPE = Pc.EVRange; data: State.GSHandle ← State.GetGS[]; cache: CacheBase ← Storage.Pages[1]; Head, Free: Item; ItemNull: Item = LAST[Item]; CacheLimit: CARDINAL = (MachineDefs.PageSize/SIZE[ItemObject])*SIZE[ItemObject]; CacheBase: TYPE = BASE POINTER TO UNSPECIFIED; Item: TYPE = CacheBase RELATIVE POINTER [0..256) TO ItemObject; ItemObject: TYPE = RECORD [ link: Item, ep: EVRange, gf: GFHandle, start, end: BytePC, hasSons: BOOLEAN, inner: BOOLEAN, dCbti: CBTIndex, userCbti: CBTIndex]; 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; Enumerate: PROC [proc: PROC [Item] RETURNS [BOOLEAN], gf: GFHandle] RETURNS [i: Item] = BEGIN next, last: Item; FOR i ← Head, cache[i].link UNTIL i = ItemNull DO IF cache[i].gf = gf AND proc[i] THEN BEGIN IF i = Head THEN RETURN; cache[last].link ← cache[i].link; cache[i].link ← Head; Head ← i; RETURN END; last ← i; ENDLOOP; IF Free # ItemNull THEN RETURN; FOR i ← Head, next UNTIL i = last DO IF (next ← cache[i].link) # last THEN LOOP; cache[i].link ← ItemNull; cache[last].link ← Free; Free ← next; RETURN[ItemNull]; ENDLOOP; END; FindEp: PROC [ep: EVRange, gf: GFHandle] RETURNS [Item] = BEGIN Find: PROC [i: Item] RETURNS [BOOLEAN] = {RETURN[ep = cache[i].ep]}; RETURN[Enumerate[Find, gf]]; END; FindPC: PROC [pc: BytePC, gf: GFHandle] RETURNS [Item] = BEGIN Find: PROC [i: Item] RETURNS [BOOLEAN] = BEGIN RETURN[ Card[pc] >= Card[cache[i].start] AND Card[pc] <= Card[cache[i].end]] END; RETURN[Enumerate[Find, gf]]; END; FindCbti: PROC [cbti: CBTIndex] RETURNS [i: Item] = BEGIN FOR i ← Head, cache[i].link UNTIL i = ItemNull DO IF cache[i].dCbti = cbti THEN RETURN; ENDLOOP; END; EvalStackEmpty: PUBLIC PROCEDURE [sp: PrincOps.SVPointer ← NIL] RETURNS [BOOLEAN] = BEGIN SV: TYPE = RECORD [inst,ptr: MachineDefs.BYTE]; sv: SV; IF sp = NIL THEN sp ← data.StatePtr; IF sp = NIL THEN RETURN[TRUE]; sv ← DebugOps.ShortREAD[sp+8]; -- yech RETURN [sv.ptr = 0] END; Son: PUBLIC PROC [cbti: CBTIndex] RETURNS [BOOLEAN] = BEGIN i: Item ← FindCbti[cbti]; IF i = ItemNull THEN ERROR NoBti; RETURN [cache[i].hasSons]; 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 [pc: BytePC] RETURNS [CARDINAL] = INLINE {RETURN[LOOPHOLE[pc]]}; GetPc: PROC [gf: GFHandle, i: EVRange] RETURNS [pc: BytePC] = BEGIN OPEN PrincOps; -- CSegP: TYPE = POINTER TO MachineDefs.CSegPrefix; -- gf, LOOPHOLE[@LOOPHOLE[0,CSegP].entry[i].initialpc]]; InitialPcOffset: CARDINAL = 0; wpc: INTEGER ← DebugOps.ReadCodeWord[ gf, SIZE[PrefixHeader]+i*SIZE[EntryVectorItem]+InitialPcOffset]; odd: BOOLEAN ← wpc < 0; pc ← [ABS[wpc]*2+LOOPHOLE[odd, INTEGER]]; END; GetEp: PROC [pc: BytePC, gf: GFHandle, mdi: MDIndex] RETURNS [ep: EVRange, start: BytePC] = BEGIN i, maxEp: EVRange; diff: CARDINAL ← LAST[CARDINAL]; last: BytePC; maxEp ← EVSize[mdi]; FOR i IN [0..maxEp] DO last ← 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; ENDLOOP; RETURN; END; Ep: PUBLIC PROC [pc: BytePC, gf: GFHandle] RETURNS [ep: EVRange, start: BytePC] = BEGIN old: Item ← FindPC[pc, gf]; mdi: MDIndex; IF old # ItemNull THEN RETURN[cache[old].ep, cache[old].start]; mdi ← DSyms.GFrameMdi[gf]; [ep, start] ← GetEp[pc,gf,mdi]; [] ← ConvertEp[ep,start,gf,mdi]; RETURN; END; EpToCBti: PUBLIC PROC [ ep: EVRange, gf: GFHandle, start: BytePC ← Pc.NullPC] RETURNS [cbti: CBTIndex] = BEGIN old: Item ← FindEp[ep, gf]; IF old # ItemNull THEN RETURN[cache[old].dCbti]; cbti ← cache[ConvertEp[ep,start,gf,DSyms.GFrameMdi[gf ! SegmentDefs.InvalidFP, SymbolTable.Missing, Frames.Invalid => GOTO exit]]].dCbti; EXITS exit => RETURN [CBTNull] END; CacheCBti: PUBLIC PROC [mdi: MDIndex, gf: GFHandle, cbti: CBTIndex] RETURNS [dCbti: CBTIndex, initialPc: BytePC] = BEGIN ep: EVRange; i: Item; FillInEp: PROC [base: SymbolTable.Base] = {ep ← base.bb[cbti].entryIndex}; Copier.Outer[mdi,FillInEp]; initialPc ← 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 ← 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 ← 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; Fixup: PROC [pc: BytePC, gf: GFHandle] RETURNS [BytePC, GFHandle] = BEGIN IF gf = NIL THEN gf ← State.GF[]; IF pc = Pc.NullPC THEN pc ← GetPc[gf,0]; RETURN[pc,gf]; END; ParentCbti: PROC [pc: BytePC, gf: GFHandle] RETURNS [old: Item, mdi: MDIndex] = BEGIN ep: EVRange; start: BytePC; old ← FindPC[pc,gf]; mdi ← DSyms.GFrameMdi[gf ! SegmentDefs.InvalidFP, SymbolTable.Missing, Frames.Invalid => GOTO noSyms]; IF old = ItemNull THEN BEGIN [ep, start] ← GetEp[pc,gf,mdi]; old ← ConvertEp[ep,start,gf,mdi]; END; RETURN; EXITS noSyms => {mdi ← Symbols.MDNull; RETURN}; END; ConvertCbti: 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; Bti: PUBLIC PROC [pc: BytePC ← Pc.NullPC, gf: GFHandle ← MachineDefs.NullGF] RETURNS [bti: BTIndex] = BEGIN mdi: MDIndex; lpc: BytePC; lgf: GFHandle; i: Item; ClosestBti: PROC [base: SymbolTable.Base] = BEGIN bti ← ConvertCbti[bti,pc,cache[i].start,base]; END; [lpc,lgf] ← Fixup[pc,gf]; [i,mdi] ← ParentCbti[lpc,lgf]; IF mdi = Symbols.MDNull OR i = ItemNull THEN RETURN[BTNull]; IF (bti ← cache[i].userCbti) = BTNull THEN RETURN; IF ~cache[i].hasSons THEN RETURN; Copier.Outer[mdi,ClosestBti]; END; CBti: PUBLIC PROC [ pc: BytePC ← Pc.NullPC, gf: GFHandle ← MachineDefs.NullGF] RETURNS [cbti: CBTIndex] = BEGIN lpc: BytePC; lgf: GFHandle; i: Item; [lpc,lgf] ← Fixup[pc,gf]; IF (i ← ParentCbti[lpc, lgf].old) = ItemNull THEN RETURN[CBTNull]; RETURN[cache[i].dCbti]; END; ContextList: PUBLIC PROC [ pc: BytePC, gf: GFHandle, why: Pc.Reason, ex: DebugFormat.EXOI ← in] RETURNS [mapped: Pc.CtxLink] = BEGIN bti: BTIndex ← Bti[pc,gf]; mdi: Symbols.MDIndex ← DSyms.GFrameMdi[gf]; list: Pc.CtxLink; Base: PROC [base: SymbolTable.Base] = {list ← Walk[base,bti,NIL,why,ex]}; Copier.Outer[mdi,Base]; mapped ← NIL; IF why = search THEN BEGIN FOR i: Pc.CtxLink ← list, i.link UNTIL i = NIL DO i.ictx ← DI.MapCtx[mdi,i.ctx]; ENDLOOP; mapped ← list; END ELSE BEGIN FOR i: Pc.CtxLink ← list, i.link UNTIL i = NIL DO mapped ← AddToList[mapped, DI.MapCtx[mdi,i.ctx]]; ENDLOOP; Pc.FreeContextList[list]; END; END; Walk: PROC [ base: SymbolTable.Base, bti: Symbols.BTIndex, oldList: Pc.CtxLink, why: Pc.Reason, ex: DebugFormat.EXOI] RETURNS [newList: Pc.CtxLink] = BEGIN myBti: Symbols.BTIndex = bti; added: BOOLEAN ← FALSE; WITH body: base.bb[bti] SELECT FROM Callable => IF why = search AND body.level = Symbols.lG THEN RETURN[oldList] ELSE BEGIN newList ← AddToList[oldList, body.localCtx]; IF why = print THEN RETURN; added ← TRUE; WITH base.seb[body.ioType] SELECT FROM transfer => BEGIN newList ← AddRecord[newList, base, LOOPHOLE[outRecord], ex = exit]; newList ← AddRecord[newList, base, LOOPHOLE[inRecord], ex = entry]; ex ← in; END; ENDCASE => ERROR NotCallable; END; ENDCASE => newList ← oldList; IF (bti ← base.ParentBti[bti]) = Symbols.BTNull THEN RETURN; newList ← Walk[base,bti,newList,why,ex]; IF ~added THEN newList ← AddToList[newList, base.bb[myBti].localCtx]; END; AddToList: PROC [list: Pc.CtxLink, ctx: Symbols.CTXIndex] RETURNS [newList: Pc.CtxLink] = BEGIN newList ← Storage.Node[SIZE[Pc.CtxItem]]; newList↑ ← [link: list, onStack: FALSE, context: user[ctx: ctx]]; END; AddRecord: PROC [ list: Pc.CtxLink, base: SymbolTable.Base, rsei: Symbols.RecordSEIndex, onStack: BOOLEAN] RETURNS [newList: Pc.CtxLink] = BEGIN ctx: Symbols.CTXIndex; IF rsei = Symbols.RecordSENull THEN RETURN [list]; ctx ← base.seb[rsei].fieldCtx; newList ← Storage.Node[SIZE[Pc.CtxItem]]; newList↑ ← [link: list, onStack: onStack, context: user[ctx: ctx]]; RETURN; END; EntryPC: PUBLIC PROC [ep: EVRange, gf: GFHandle, noSyms: BOOLEAN ← FALSE] RETURNS [pc: BytePC] = BEGIN i: Item; cbti: CBTIndex; mdi: MDIndex; FirstFGTEntry: PROC [base: SymbolTable.Base] = BEGIN j: CARDINAL; WITH base.bb[cbti].info SELECT FROM External => FOR j IN (startIndex..startIndex+indexLength) DO WITH entry: base.fgTable[j] SELECT FROM normal => {pc ← [pc + entry.deltaObject]; EXIT}; step => IF entry.which = object THEN {pc ← [pc + entry.delta]; EXIT}; ENDCASE; ENDLOOP; ENDCASE; END; pc ← GetPc[gf,ep]; IF noSyms THEN RETURN; mdi ← DSyms.GFrameMdi[gf, TRUE ! DSyms.NoFGT => GOTO ret]; IF (i ← FindEp[ep,gf]) = ItemNull THEN i ← ConvertEp[ep,pc,gf,mdi]; IF (cbti ← cache[i].userCbti) = CBTNull THEN RETURN; Copier.Outer[mdi,FirstFGTEntry]; EXITS ret => RETURN; END; ExitPC: PUBLIC PROC [cbti: CBTIndex] RETURNS [BytePC] = BEGIN RETURN[cache[FindCbti[cbti]].end] END; CbtiItem: PROC [f: FHandle, pc: BytePC] RETURNS [Item, BytePC] = BEGIN SELECT TRUE FROM f = NIL => BEGIN f ← State.LF[]; pc ← Lf.PC[f] END; pc = Pc.NullPC => pc ← Lf.PC[f]; ENDCASE; RETURN[FindCbti[CBti[pc, Lf.GF[f]]], pc]; END; Entry: PUBLIC PROCEDURE [ f: FHandle ← NIL, pc: BytePC ← Pc.NullPC] RETURNS [BOOLEAN] = BEGIN i: Item; [i,pc] ← CbtiItem[f,pc]; IF i = ItemNull THEN ERROR SymbolTable.Missing[NIL]; RETURN[(cache[i].start = pc) OR (cache[i].inner AND Card[cache[i].start]+2 = Card[pc])]; END; Exit: PUBLIC PROCEDURE [ f: FHandle ← NIL, pc: BytePC ← Pc.NullPC] RETURNS [BOOLEAN] = BEGIN i: Item; [i,pc] ← CbtiItem[f,pc]; IF i = ItemNull THEN ERROR SymbolTable.Missing[NIL]; RETURN[cache[i].end = pc]; END; END.