<<>> <> <> <> <> <> DIRECTORY Alloc USING [AddNotify, Base, DropNotify, Handle, Index, Notifier, Top], MobDefs USING [Link, VersionStamp], CompilerUtil USING [AcquireStream, ReleaseStream], ConvertUnsafe USING [SubString, ToRope], IO USING [Put1, PutChar, PutF1, PutRope, STREAM], Literals USING [Base, LitDescriptor, LitClass, LTIndex, ltType], LiteralOps USING [DescriptorValue, IsShort, MasterString, StringValue, Value, ValueBits, ValueInt, ValueReal], MessageTab USING [ModePrintName, NodePrintName, TypePrintName], MimData USING [wordAlignment], Rope USING [ROPE], Symbols USING [Base, BitAddress, bodyType, BTIndex, CSEIndex, CTXFirst, CTXIndex, CTXNull, CTXRecord, ctxType, ISEIndex, lG, lZ, mdType, Name, nullName, RootBti, SEIndex, SENull, SERecord, seType, TransferMode, TypeClass, typeTYPE], SymbolOps USING [CtxLevel, DecodeBitAddr, DecodeCard, DecodeInt, DecodeLink, DecodeType, EnumerateBodies, FindExtension, NameForSe, NextSe, own, SubStringForName, TypeLink, XferMode], Table USING [IndexRep], Target: TYPE MachineParms USING [bitOrder, bitsPerByte, bitsPerLongWord], Tree USING [Base, Index, Link, NodeName, Scan, nullIndex, nullInfo, treeType], TreeOps USING [GetNode, GetTag, ScanSons]; MimosaDebug: PROGRAM IMPORTS Alloc, CompilerUtil, ConvertUnsafe, IO, LiteralOps, MessageTab, MimData, SymbolOps, TreeOps EXPORTS CompilerUtil = { OPEN Symbols; ROPE: TYPE = Rope.ROPE; STREAM: TYPE = IO.STREAM; tb: Tree.Base; seb: Symbols.Base; ctxb: Symbols.Base; mdb: Symbols.Base; bb: Symbols.Base; ltb: Literals.Base; definitionsOnly: BOOL ¬ FALSE; DebugNotify: Alloc.Notifier = { tb ¬ base[Tree.treeType]; seb ¬ base[seType]; ctxb ¬ base[ctxType]; mdb ¬ base[mdType]; bb ¬ base[bodyType]; ltb ¬ base[Literals.ltType]; }; SubString: TYPE = ConvertUnsafe.SubString; bytesPerLongWord: NAT = Target.bitsPerLongWord/Target.bitsPerByte; <> errorStream: STREAM ¬ NIL; oldStream: STREAM ¬ NIL; logStream: STREAM ¬ NIL; WriteBool: PROC [prefix: ROPE, b: BOOL] = { IF prefix # NIL THEN IO.PutRope[errorStream, prefix]; IO.PutRope[errorStream, IF b THEN "TRUE" ELSE "FALSE"]; }; WriteChar: PROC [c: CHAR] = INLINE { IO.PutChar[errorStream, c]; }; WriteRope: PROC [r: ROPE] = INLINE { IO.PutRope[errorStream, r]; }; WriteRopeInt: PROC [r: ROPE, n: INT] = INLINE { IO.PutF1[errorStream, r, [integer[n]] ]; }; WriteRopeCard: PROC [r: ROPE, c: CARD] = INLINE { IO.PutF1[errorStream, r, [cardinal[c]] ]; }; WriteInt: PROC [n: INT] = INLINE { IO.Put1[errorStream, [integer[n]]]; }; NewLine: PROC [n: NAT ¬ 1] = INLINE { IF n > 2 THEN THROUGH [2..n) DO WriteChar['\n]; ENDLOOP; IF n > 1 THEN WriteChar['\n]; WriteChar['\n]; }; Indent: PROC [n: CARDINAL] = { NewLine[]; THROUGH [1..n/8] DO WriteRope[" "] ENDLOOP; THROUGH [1..n MOD 8] DO WriteChar[' ] ENDLOOP; }; <> Enter: PROC [table: Alloc.Handle, st: STREAM ¬ NIL] = { table.AddNotify[DebugNotify]; IF st # NIL THEN { oldStream ¬ errorStream; errorStream ¬ st; logStream ¬ NIL; } ELSE { oldStream ¬ NIL; logStream ¬ errorStream ¬ CompilerUtil.AcquireStream[log]; }; definitionsOnly ¬ FALSE; }; Exit: PROC [table: Alloc.Handle] = { definitionsOnly ¬ FALSE; IF logStream # NIL THEN CompilerUtil.ReleaseStream[log]; errorStream ¬ oldStream; oldStream ¬ NIL; logStream ¬ NIL; table.DropNotify[DebugNotify]; }; <> PrintLiteral: PROC [t: Tree.Link.literal] = { lti: Literals.LTIndex = t.index; IF LiteralOps.IsShort[lti] THEN { class: Literals.LitClass ¬ LiteralOps.Value[lti].class; SELECT class FROM signed, either => WriteInt[LiteralOps.ValueInt[lti]]; real => IO.PutF1[errorStream, "%g", [real[LiteralOps.ValueReal[lti]]]]; ENDCASE => IO.PutF1[errorStream, "%bB", [cardinal[LiteralOps.ValueBits[lti]]]]; } ELSE { desc: Literals.LitDescriptor = LiteralOps.DescriptorValue[t.index]; WriteChar['[]; FOR i: CARDINAL IN [0 .. desc.words) DO IF i # 0 THEN WriteChar[',]; IO.PutF1[errorStream, "%b", [cardinal[SymbolOps.DecodeCard[ltb[desc.offset][i]]]]]; ENDLOOP; WriteChar[']]; }; }; PrintString: PROC [t: Tree.Link.string] = { s: LONG STRING = LiteralOps.StringValue[t.index]; WriteChar['"]; FOR i: CARDINAL IN [0..s.length) DO WriteChar[s[i]] ENDLOOP; WriteChar['"]; IF t.index # LiteralOps.MasterString[t.index] THEN WriteChar['L]; }; WriteNodeName: PROC [n: Tree.NodeName] = INLINE { IO.PutRope[errorStream, MessageTab.NodePrintName[n]]; }; PrintSubTree: PROC [t: Tree.Link, nBlanks: CARDINAL] = { OPEN Tree; Printer: Tree.Scan = { Indent[nBlanks]; WITH s: t SELECT TreeOps.GetTag[t] FROM hash => PrintName[NIL, s.index]; symbol => {PrintSei[NIL, s.index]; PrintIndex["[", s.index]; WriteChar[']]}; literal => PrintLiteral[s]; string => PrintString[s]; subtree => { node: Tree.Index = s.index; IF node = Tree.nullIndex THEN WriteRope[""] ELSE { OPEN tb[node]; WriteNodeName[name]; PrintIndex["[", node]; WriteRope["] "]; IF info # Tree.nullInfo THEN PrintIndex[" info=", LOOPHOLE[info]]; IF attr1 OR attr2 OR attr3 THEN { IF info = Tree.nullInfo THEN WriteChar[' ]; WriteChar['(]; IF attr1 THEN WriteChar['1]; IF attr2 THEN WriteChar['2]; IF attr3 THEN WriteChar['3]; WriteChar[')]; }; IF tb[node].subInfo # 0 THEN WriteRopeInt[" <<%g>>", tb[node].subInfo]; nBlanks ¬ nBlanks + 2; IF name # thread THEN TreeOps.ScanSons[s, Printer] ELSE { PrintIndex[" link=", TreeOps.GetNode[son[2]]]; Printer[son[1]]; }; nBlanks ¬ nBlanks - 2; }; }; ENDCASE; }; Printer[t]; }; PrintTree: PUBLIC PROC [table: Alloc.Handle, root: Tree.Link] = { Enter[table]; PrintSubTree[root, 0]; NewLine[2]; Exit[table]; }; PrintBodies: PUBLIC PROC [table: Alloc.Handle] = { Enter[table]; [] ¬ SymbolOps.EnumerateBodies[SymbolOps.own, RootBti, PrintBody]; NewLine[]; Exit[table]; }; PrintBody: PROC [bti: BTIndex] RETURNS [BOOL] = { OPEN body: bb[bti]; WriteRope["Body: "]; WITH b: body SELECT FROM Callable => { PrintSei[NIL, b.id]; IF b.inline THEN WriteRope[" [inline]"] ELSE { SELECT b.kind FROM Outer => WriteRope[" (Outer)"]; Inner => WriteRope[" (Inner)"]; Catch => WriteRope[" (Catch)"]; ENDCASE => WriteRope[" (Other)"]; WriteRopeInt[", ep: %g", b.entryIndex]; WriteRopeInt[", frame addr: %g", b.frameOffset]; }; WriteRope[", attrs: "]; WriteChar[IF ~b.noXfers THEN 'x ELSE '-]; WriteChar[IF b.hints.safe THEN 's ELSE '-]; WriteChar[IF b.hints.nameSafe THEN 'n ELSE '-]; IF ~b.hints.noStrings THEN {Indent[2]; WriteRope["string literals"]}; }; ENDCASE => WriteRope["(anon)"]; Indent[2]; PrintIndex["context: ", body.localCtx]; WriteRopeInt[", level: %g", body.level]; WITH body.info SELECT FROM Internal => { WriteRopeInt[", frame size: %g", frameSize]; IF body.kind = Callable THEN PrintSubTree[[subtree[index: bodyTree]], 0] ELSE PrintIndex[", tree root: ", bodyTree]; }; ENDCASE; NewLine[2]; RETURN [FALSE]; }; PrintSymbols: PUBLIC PROC [table: Alloc.Handle, definitions: BOOL] = { ctx: CTXIndex; limit: CTXIndex; Enter[table]; definitionsOnly ¬ definitions; -- must be after Enter limit ¬ table.Top[Symbols.ctxType]; ctx ¬ CTXFirst + CTXRecord.nil.SIZE; UNTIL ctx = limit DO PrintContext[ctx]; NewLine[2]; ctx ¬ ctx + (WITH ctxb[ctx] SELECT FROM included => CTXRecord.included.SIZE, imported => CTXRecord.imported.SIZE, ENDCASE => CTXRecord.simple.SIZE); ENDLOOP; NewLine[]; Exit[table]; }; PrintContext: PROC [ctx: CTXIndex] = { sei, root: ISEIndex; PrintIndex["Context: ", ctx]; IF SymbolOps.CtxLevel[SymbolOps.own, ctx] # lZ THEN WriteRopeInt[", level: %g", SymbolOps.CtxLevel[SymbolOps.own, ctx]]; WITH c: ctxb[ctx] SELECT FROM included => { PrintName[", copied from: ", mdb[c.module].moduleId]; PrintName[" [", mdb[c.module].fileId]; PrintVersion[", ", mdb[c.module].stamp]; PrintIndex["], context: ", c.map]; }; imported => PrintName[", imported from: ", mdb[ctxb[c.includeLink].module].moduleId]; ENDCASE; root ¬ sei ¬ ctxb[ctx].seList; DO IF sei = SENull THEN EXIT; PrintSE[sei, 2]; IF (sei ¬ SymbolOps.NextSe[SymbolOps.own, sei]) = root THEN EXIT; ENDLOOP }; PrintSE: PROC [sei: ISEIndex, nBlanks: CARDINAL] = { sep: LONG POINTER TO SERecord.id = @seb[sei]; typeSei: SEIndex; Indent[nBlanks]; PrintSei[NIL, sei]; PrintIndex[" [", sei]; WriteChar[']]; IF sep.public THEN WriteRope[" [public]"]; IF sep.mark3 THEN { IF sep.idType = typeTYPE THEN { typeSei ¬ SymbolOps.DecodeType[sep.idInfo]; PrintType[", type = TYPE, equated to: ", typeSei]; IF SymbolOps.CtxLevel[SymbolOps.own, sep.idCtx] = lZ AND SymbolOps.TypeLink[SymbolOps.own, sei] # SENull THEN WriteRopeInt[", tag code: %g", SymbolOps.DecodeInt[sep.idValue]]; } ELSE { typeSei ¬ sep.idType; PrintType[", type = ", typeSei]; SELECT TRUE FROM sep.constant => WriteRope[" [const]"]; sep.immutable => WriteRope[" [init only]"]; ENDCASE; IF ~sep.mark4 THEN WriteRopeInt[", # refs: %g", SymbolOps.DecodeInt[sep.idInfo]] ELSE SELECT TRUE FROM sep.constant => IF NOT sep.extended AND seb[typeSei].mark3 THEN { WriteRope[", value: "]; SELECT SymbolOps.XferMode[SymbolOps.own, typeSei] FROM proc, program, signal, error => PrintLink[SymbolOps.DecodeLink[sep.idValue]]; ENDCASE => { val: CARD = SymbolOps.DecodeCard[sep.idValue]; IF val < 1000 THEN WriteInt[val] ELSE IO.PutF1[errorStream, "%bB", [cardinal[val]]]; }; }; (definitionsOnly AND SymbolOps.CtxLevel[SymbolOps.own, sep.idCtx] = lG) => WriteRopeInt[", index: %g", SymbolOps.DecodeInt[sep.idValue]]; sep.linkSpace => { WriteRope[", "]; PrintLink[SymbolOps.DecodeLink[sep.idValue]]; }; ENDCASE => { addr: BitAddress = SymbolOps.DecodeBitAddr[sep.idValue]; WriteRopeInt[", address: %g[", addr]; WriteRopeInt["%g]", SymbolOps.DecodeInt[sep.idInfo]]; }; }; PrintTypeInfo[typeSei, nBlanks+2]; IF sep.extended THEN PrintSubTree[SymbolOps.FindExtension[SymbolOps.own, sei].tree, nBlanks+4]; }; }; PrintName: PROC [prefix: ROPE, name: Name] = { IF prefix # NIL THEN WriteRope[prefix]; IF name = nullName THEN WriteRope["(anon)"] ELSE { s: SubString ¬ SymbolOps.SubStringForName[SymbolOps.own, name]; FOR i: CARDINAL IN [s.offset..s.offset+s.length) DO WriteChar[s.base[i]]; ENDLOOP; }; }; PrintSei: PROC [prefix: ROPE, sei: ISEIndex] = { PrintName[prefix, SymbolOps.NameForSe[SymbolOps.own, sei]]; }; WriteTypeName: PROC [n: TypeClass] = INLINE { IO.PutRope[errorStream, MessageTab.TypePrintName[n]]; }; WriteModeName: PROC [n: TransferMode] = INLINE { IO.PutRope[errorStream, MessageTab.ModePrintName[n]]; }; PrintType: PROC [prefix: STRING, sei: SEIndex] = { tSei: SEIndex; IF prefix # NIL THEN WriteRope[ConvertUnsafe.ToRope[prefix]]; IF sei = SENull THEN WriteChar['?] ELSE WITH t: seb[sei] SELECT FROM cons => WITH t SELECT FROM transfer => WriteModeName[mode]; ENDCASE => WriteTypeName[t.typeTag]; id => FOR tSei ¬ sei, SymbolOps.TypeLink[SymbolOps.own, tSei] UNTIL tSei = SENull DO WITH seb[tSei] SELECT FROM id => { IF sei # tSei THEN WriteChar[' ]; PrintSei[NIL, LOOPHOLE[tSei, ISEIndex]]; IF ~mark3 OR SymbolOps.CtxLevel[SymbolOps.own, idCtx] # lZ THEN EXIT; }; ENDCASE; ENDLOOP; ENDCASE; PrintIndex[" [", sei]; WriteChar[']]; }; PrintTypeInfo: PROC [sei: SEIndex, nBlanks: CARDINAL] = { IF sei # SENull THEN { sep: LONG POINTER TO Symbols.SERecord = @seb[sei]; WITH s: sep­ SELECT FROM id => { PrintSE[LOOPHOLE[sei, ISEIndex], nBlanks]; }; cons => { option: BOOL ¬ FALSE; PutOption: PROC [name: ROPE] = { IF option THEN WriteRope[", "] ELSE {WriteRope[" ("]; option ¬ TRUE}; WriteRope[name]; }; EndOption: PROC = { IF option THEN {WriteRope[")"]; option ¬ FALSE}; }; Indent[nBlanks]; PrintIndex["[", sei]; WriteRope["] "]; WITH s SELECT FROM transfer => WriteModeName[mode]; ENDCASE => WriteTypeName[s.typeTag]; WITH t: s SELECT FROM basic => { WriteRopeInt[" (code: %g", t.code]; WriteRopeInt[", bits: %g", t.length]; IF t.ordered THEN WriteBool[", ordered: ", t.ordered]; WriteChar[')]; }; enumerated => { IF t.machineDep THEN PutOption["md"]; IF ~t.painted THEN PutOption["~painted"]; IF t.sparse THEN PutOption["sparse"]; IF t.ordered THEN PutOption["ordered"]; IF t.empty THEN PutOption["empty"]; EndOption[]; PrintIndex[", value ctx: ", t.valueCtx]; }; record => { IF t.packed THEN PutOption["packed"]; IF t.list THEN PutOption["list"]; IF t.machineDep THEN { PutOption["md["]; WriteRope[IF t.bitOrder = msBit THEN "msBit" ELSE "lsBit"]; WriteRopeInt[": %g]", t.grain]; }; IF t.monitored THEN PutOption["monitored"]; IF t.hints.variant THEN PutOption["variant"]; IF t.align # MimData.wordAlignment THEN SELECT t.align FROM none => PutOption["noAlign"]; oneAU => PutOption["oneAU"]; twoAU => PutOption["twoAU"]; fourAU => PutOption["fourAU"]; eightAU => PutOption["eightAU"]; ENDCASE => PutOption["align?"]; EndOption[]; OutCtx[", field", t.fieldCtx]; WITH ctxb[t.fieldCtx] SELECT FROM included => IF ~complete THEN WriteRope[" [partial]"]; imported => WriteRope[" [partial]"]; ENDCASE; WITH t SELECT FROM linked => PrintType[", link: ", linkType]; ENDCASE; }; ref => { IF t.counted THEN PutOption["counted"]; IF t.var THEN PutOption["var"]; IF t.ordered THEN PutOption["ordered"]; IF t.basing THEN PutOption["base"]; IF t.list THEN PutOption["list"]; EndOption[]; PrintType[", to: ", t.refType]; IF t.readOnly THEN WriteRope[" (readonly)"]; PrintTypeInfo[t.refType, nBlanks+2]; }; array => { IF t.packed THEN PutOption["packed"]; SELECT t.bitOrder FROM msBit => IF Target.bitOrder # msBit THEN PutOption["msBit"]; lsBit => IF Target.bitOrder # lsBit THEN PutOption["lsBit"]; ENDCASE; EndOption[]; PrintType[", index type: ", t.indexType]; PrintType[", component type: ", t.componentType]; PrintTypeInfo[t.indexType, nBlanks+2]; PrintTypeInfo[t.componentType, nBlanks+2]; }; arraydesc => { PrintType[", described type: ", t.describedType]; IF t.readOnly THEN PutOption["readonly"]; SELECT t.bitOrder FROM msBit => IF Target.bitOrder # msBit THEN PutOption["msBit"]; lsBit => IF Target.bitOrder # lsBit THEN PutOption["lsBit"]; ENDCASE; EndOption[]; PrintTypeInfo[t.describedType, nBlanks+2]; }; transfer => { IF t.safe THEN PutOption["safe"]; EndOption[]; OutArgType[", input", t.typeIn]; OutArgType[", output", t.typeOut]; }; definition => { PrintIndex[", ctx: ", t.defCtx]; WriteRopeInt[", slots: %g", t.slots]; }; union => { IF t.overlaid THEN PutOption["overlaid"]; IF t.machineDep THEN PutOption["md"]; EndOption[]; IF t.controlled THEN PrintSei[", tag: ", t.tagSei]; PrintType[", tag type: ", seb[t.tagSei].idType]; PrintIndex[", case ctx: ", t.caseCtx]; IF t.controlled THEN PrintSE[t.tagSei, nBlanks+2]; }; sequence => { IF t.packed THEN PutOption["packed"]; IF t.machineDep THEN PutOption["md"]; EndOption[]; PrintType[", parent: ", t.parentType]; IF t.controlled THEN PrintSei[", tag: ", t.tagSei] ELSE PrintType[", index type: ", seb[t.tagSei].idType]; PrintType[", component type: ", t.componentType]; IF t.controlled THEN PrintSE[t.tagSei, nBlanks+2] ELSE PrintTypeInfo[seb[t.tagSei].idType, nBlanks+2]; PrintTypeInfo[t.componentType, nBlanks+2]; }; relative => { PrintType[", base type: ", t.baseType]; PrintType[", offset type: ", t.offsetType]; PrintTypeInfo[t.baseType, nBlanks+2]; PrintTypeInfo[t.offsetType, nBlanks+2]; }; opaque => { PrintSei[", id: ", t.id]; IF t.lengthKnown THEN WriteRopeInt[", length: %g", t.length]; }; zone => { IF t.counted THEN PutOption["counted"]; IF t.mds THEN PutOption["mds"]; EndOption[]; }; subrange => { IF NOT t.filled THEN PutOption["~filled"]; IF t.origin < 0 AND NOT t.biased THEN PutOption["unbiased"]; IF t.empty THEN PutOption["empty"]; EndOption[]; PrintType[" of: ", t.rangeType]; IF t.filled THEN { WriteRopeInt[" origin: %g", t.origin]; WriteRopeCard[", range: %g", t.range]; }; PrintTypeInfo[t.rangeType, nBlanks+2]; }; real => WriteRopeInt[" (bits: %g)", t.length]; signed => WriteRopeInt[" (bits: %g)", t.length]; unsigned => WriteRopeInt[" (bits: %g)", t.length]; ENDCASE; }; ENDCASE; }; }; OutCtx: PROC [prefix: ROPE, ctx: CTXIndex] = { WriteRope[prefix]; IF ctx = CTXNull THEN WriteRope[" ctx: NIL"] ELSE PrintIndex[" ctx: ", ctx]; }; OutArgType: PROC [prefix: ROPE, sei: CSEIndex] = { WriteRope[prefix]; IF sei = SENull THEN WriteRope[": NIL"] ELSE WITH t: seb[sei] SELECT FROM record => OutCtx[NIL, t.fieldCtx]; any => WriteRope[": ANY"]; ENDCASE; }; PrintIndex: PROC [prefix: ROPE, v: Alloc.Index] = { tagged: Table.IndexRep ¬ LOOPHOLE[v]; int: INT ¬ LOOPHOLE[tagged]; WriteRope[prefix]; SELECT tagged.tag FROM 0, 255 => { <> }; ENDCASE => { WriteRopeInt["%g:", tagged.tag]; tagged.tag ¬ 0; int ¬ LOOPHOLE[tagged]; }; WriteInt[int]; }; PrintLink: PROC [link: MobDefs.Link] = { SELECT link.tag FROM var => WriteRope["var["]; proc => WriteRope["proc["]; type => WriteRope["type["]; other => WriteRope["other["]; ENDCASE => ERROR; WriteRopeInt["mod: %g", link.modIndex]; WriteRopeInt[", offset: %g]", link.offset]; }; << PrintVersion: PROC [prefix: ROPE, stamp: MobDefs.VersionStamp] = { stampWords: CARDINAL = MobDefs.VersionStamp.SIZE; str: PACKED ARRAY [0..4*stampWords) OF [0..16) = LOOPHOLE[stamp]; digit: STRING = "0123456789abcdef"L; WriteRope[prefix]; FOR i: NAT IN [0..4*stampWords) DO WriteChar[digit[str[i]]] ENDLOOP; };>> PrintVersion: PROC [prefix: Rope.ROPE, stamp: MobDefs.VersionStamp] = { stampBytes: CARDINAL = BYTES[MobDefs.VersionStamp]; str: PACKED ARRAY [0..2*stampBytes) OF [0..16) = LOOPHOLE[stamp]; digit: STRING = "0123456789abcdef"L; WriteRope[prefix]; FOR i: NAT IN [0..2*stampBytes) DO WriteChar[digit[str[i]]] ENDLOOP; }; }.