-- HeapPrint.mesa -- Andrew Birrell August 12, 1982 1:16 pm DIRECTORY Directory, File, HeapXDefs, ObjectDirDefs, IO, Rope USING[ ROPE ], Space; HeapPrint: PROGRAM IMPORTS Directory, File, IO, Space SHARES ObjectDirDefs = BEGIN -- Heap.chain -- segmentCount: CARDINAL = 200; -- number of segments in message body file -- Segment: TYPE = [0..segmentCount); SegmentPtr: TYPE = [ FIRST[Segment] .. 1+LAST[Segment] ]; noSegment: SegmentPtr = LAST[SegmentPtr]; -- the 'free' and 'written' chains are stored permanently on a disk page-- PageType: TYPE = RECORD[written: ARRAY[0..0]OF SegmentPtr --for alignment--, free: ARRAY[0..0]OF SegmentPtr --for alignment--, ser: LONG INTEGER, next: ARRAY Segment OF SegmentPtr]; ChainPage: TYPE = LONG POINTER TO PageType; chain: ChainPage; segSize: CARDINAL; fileSize: INT; GetChain: PROC = BEGIN file: File.Capability = Directory.LookupUnlimited["Heap.chain"]; space: Space.Handle = Space.Create[2, Space.virtualMemory]; chain0: ChainPage = Space.LongPointer[space]; chain1: ChainPage = Space.LongPointer[space] + 256; Space.Map[space, [file,1]]; chain ← IF chain0.ser > chain1.ser THEN chain0 ELSE chain1; segSize ← fileSize / segmentCount; END; First: PROC RETURNS[first: CARDINAL] = -- returns file-relative page number of first written page -- { first ← chain.written[0] * segSize; out.PutF["\n%g: ", [cardinal[first]]] }; NoMorePages: ERROR = CODE; Next: PROC[prev: CARDINAL] RETURNS[ next: CARDINAL ] = BEGIN IF prev MOD segSize < segSize-1 THEN { next ← prev+1; out.PutChar[IO.SP] } ELSE BEGIN seg: SegmentPtr = chain.next[prev / segSize]; IF seg = noSegment THEN ERROR NoMorePages[] ELSE BEGIN next ← seg * segSize; out.PutF["\n%g: ", [cardinal[next]]]; END; END; END; -- Heap.data -- briefType: ARRAY ObjectDirDefs.ObjectType OF Rope.ROPE = [ gap: ".", body: "B", SLinput: "S", SLpending: "S", SLforward: "S", RSobject: "R", RSmail: "RSmail", temp: "temp", RSname: "RSname", MSname : "MSname", testMode: "test", TOC: "T", archived: "A", delArch: "spare15", spare16: "spare16", spare17: "spare17" ]; fullType: ARRAY ObjectDirDefs.ObjectType OF Rope.ROPE = [ gap: "gap", body: "body", SLinput: "SLinput", SLpending: "SLpending", SLforward: "SLforward", RSobject: "RSobject", RSmail: "RSmail", temp: "temp", RSname: "RSname", MSname : "MSname", testMode: "testMode", TOC: "TOC", archived: "archived", delArch: "spare15", spare16: "spare16", spare17: "spare17" ]; in, out, textOut: IO.STREAM ← NIL; gap: ObjectDirDefs.ObjectNumber ← ObjectDirDefs.noObject; interesting: ObjectDirDefs.ObjectNumber ← -- object to watch for -- [page: 1, fill: 0, type: SLforward, index: 36]; wanted: INT ← 500; -- number of characters to print -- nextOffset: LONG CARDINAL ← 0; -- next offset to expect in current object -- current: ObjectDirDefs.ObjectNumber; pauseAtPage: CARDINAL ← LAST[CARDINAL]; -- wait for CR to be typed at that time -- watchPage: REF PACKED ARRAY NAT OF BOOL = NEW[PACKED ARRAY NAT OF BOOL ← ALL[FALSE]]; -- pages to print -- file: File.Capability = Directory.LookupUnlimited["Heap.data"]; space: Space.Handle = Space.Create[1, Space.virtualMemory]; header: LONG POINTER TO HeapXDefs.PageHeader = Space.LongPointer[space]; pageWords: LONG POINTER TO ARRAY [0..256) OF WORD = LOOPHOLE[header]; pageChars: LONG POINTER TO PACKED ARRAY [0..512) OF CHAR = LOOPHOLE[header]; Init: PROC = BEGIN fileSize ← File.GetSize[file]; GetChain[]; Space.Map[space]; [in: in, out: out] ← IO.CreateTTYStreams["Heap Summary"]; out.PutRope["For start of new object: \"B\" = body, \"S\" = steering-list, \"R\" = RSobject, \"T\" = TOC, \"A\" = archive, \"$\" = illegal object number;\n\"-\" = continuation sub-object;\n\".\" = gap sub-object;\n\"g\" = imbedded garbage;\n\"*\" = sub-object also recorded in \"Object contents\" viewer;\n<sp> between pages;\n<cr> at segment boundary.\n\n"]; END; Main: PROC = BEGIN current ← gap; FOR i: CARDINAL ← First[], Next[i ! NoMorePages => CONTINUE] DO PrintPage[i, watchPage[i]] ENDLOOP; IF current # gap THEN out.PutRope["\nUnterminated object!"]; END; PrintPage: PROC[i: CARDINAL, all: BOOL] = BEGIN word: [0..256] ← SIZE[HeapXDefs.PageHeader]; Space.CopyIn[space, [file, i+1]]; IF i = pauseAtPage THEN { out.PutRope["\nType any character to continue:"]; [] ← in.GetChar[] }; DO -- for each sub-object -- offset: LONG CARDINAL = IF word # SIZE[HeapXDefs.PageHeader] THEN 0 ELSE header.offset; objH: LONG POINTER TO HeapXDefs.ObjectHeader = LOOPHOLE[header + word]; objChars: LONG POINTER TO PACKED ARRAY [0..512) OF CHAR = LOOPHOLE[objH + SIZE[HeapXDefs.ObjectHeader]]; TypeObj: PROC[remark: Rope.ROPE] = BEGIN IF textOut = NIL THEN BEGIN [out: textOut] ← IO.CreateTTYStreams["Object contents"]; textOut.PutRope["Object: offset: size: heap-page: heap-word: remarks:\n"]; END; textOut.PutF[ "\n[p:%g,i:%g,%g]", [cardinal[objH.number.page]], [cardinal[objH.number.index]], [rope[fullType[objH.number.type]]] ]; textOut.PutF[", o:%bB, s:%bB; h:%g, w:%g, %g", [cardinal[offset]], [cardinal[objH.size]], [cardinal[i]], [cardinal[word]], [rope[remark]] ]; IF objH.number = interesting THEN BEGIN IF wanted > 0 THEN BEGIN textOut.PutChar['\n]; FOR i: INT IN [0..objH.size*2) DO textOut.PutChar[objChars[i]]; wanted ← wanted-1 ENDLOOP; END; END; out.PutChar['*]; END; SELECT TRUE FROM objH.number.page>256 OR objH.number.index>85 OR objH.number.fill#0 => { out.PutChar['$]; TypeObj["illegal"] }; objH.number = gap => out.PutChar['.]; objH.number = current => out.PutChar['-]; current # gap => out.PutChar['g]; ENDCASE => { current ← objH.number; nextOffset ← 0; out.PutRope[briefType[objH.number.type]] }; IF all THEN TypeObj["watchPage"]; IF current # gap AND objH.number = current THEN SELECT TRUE FROM offset = nextOffset => { IF objH.number = interesting THEN TypeObj["ok"]; nextOffset ← offset + objH.size }; offset < nextOffset AND nextOffset < offset + objH.size => { IF objH.number = interesting THEN TypeObj["overlap"]; nextOffset ← offset + objH.size }; offset < nextOffset => { IF objH.number = interesting THEN TypeObj["redundant"] }; offset > nextOffset => { TypeObj["****gap****"]; nextOffset ← offset + objH.size }; ENDCASE => ERROR; word ← word + SIZE[HeapXDefs.ObjectHeader]; word ← word + objH.size; IF word + SIZE[HeapXDefs.ObjectHeader] > 255 THEN EXIT; IF objH.number = current THEN current ← gap; ENDLOOP; END; Init[]; { dummy: PROCESS = FORK Main[]; }; END.