-- 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.