MODULE Info;
IMPORT
SYSTEM, Machine, Heaps, Objects, Streams, Reflection, Modules, Commands, Options, Strings, D := Debugging;
CONST
AddressSize = SYSTEM.SIZEOF(SYSTEM.ADDRESS);
RecordBlock = 1;
ProtRecBlock = 2;
ArrayBlock = 3;
SystemBlock = 4;
MaxNofTypes = 800;
SortNone = 0;
SortByCount = 1;
SortBySize = 2;
SortByTotalSize = 3;
SortByName = 4;
TYPE
Type = RECORD
ptag : SYSTEM.ADDRESS;
count : LONGINT;
size : SYSTEM.SIZE;
type : SHORTINT;
pc: SYSTEM.ADDRESS;
END;
Analyzer = OBJECT
VAR
types : POINTER TO ARRAY OF Type;
nofElements : LONGINT;
nofHeapBlocks, nofFreeBlocks, nofSystemBlocks, nofRecordBlocks, nofProtRecBlocks, nofArrayBlocks: LONGINT;
sizeHeapBlocks, sizeFreeBlocks, sizeSystemBlocks, sizeRecordBlocks, sizeProtRecBlocks, sizeArrayBlocks: SYSTEM.SIZE;
PROCEDURE &Init(size : LONGINT);
BEGIN
ASSERT(size > 0);
NEW(types, size);
Reset;
END Init;
PROCEDURE Reset;
VAR i : LONGINT;
BEGIN
nofElements := 0;
IF (types # NIL) THEN
FOR i := 0 TO LEN(types)-1 DO
types[i].ptag := Heaps.NilVal;
types[i].count := 0;
types[i].size := 0;
END;
END;
nofHeapBlocks := 0; sizeHeapBlocks := 0;
nofFreeBlocks := 0; sizeFreeBlocks := 0;
nofSystemBlocks := 0; sizeSystemBlocks := 0;
nofRecordBlocks := 0; sizeRecordBlocks := 0;
nofProtRecBlocks := 0; sizeProtRecBlocks := 0;
nofArrayBlocks := 0; sizeArrayBlocks := 0;
END Reset;
PROCEDURE SortBy(mode : LONGINT);
VAR i, j : LONGINT; temp : Type;
PROCEDURE IsGreaterThan(CONST entry1, entry2 : Type; mode : LONGINT) : BOOLEAN;
VAR name1, name2: ARRAY 256 OF CHAR; count1,count2, size1, size2: LONGINT;
BEGIN
IF mode = SortByName THEN
GetName(entry1.ptag,name1);
GetName(entry2.ptag,name2);
RETURN name1 > name2;
ELSE
count1 := entry1.count;
size1 := entry1.size DIV count1;
count2 := entry2.count;
size2 := entry2.size DIV count2;
RETURN
((mode = SortByCount) & (count1 > count2)) OR
((mode = SortBySize) & (size1 > size2)) OR
((mode = SortByTotalSize) & (size1*count1 > size2 * count2))
;
END;
END IsGreaterThan;
BEGIN
ASSERT((mode = SortByCount) OR (mode = SortBySize) OR (mode = SortByTotalSize) OR (mode=SortByName));
FOR i := 0 TO nofElements-1 DO
FOR j := 1 TO nofElements-1 DO
IF IsGreaterThan(types[j], types[j-1], mode) THEN
temp := types[j-1];
types[j-1] := types[j];
types[j] := temp;
END;
END;
END;
END SortBy;
PROCEDURE Add(CONST block : Heaps.HeapBlock; byPC: BOOLEAN);
VAR type: SHORTINT;
PROCEDURE AddByPC(type: SHORTINT);
VAR pc: SYSTEM.ADDRESS; i: LONGINT;
BEGIN
SYSTEM.GET(block.dataAdr + Heaps.HeapBlockOffset, pc);
SYSTEM.GET(pc + Heaps.HeapBlockOffset, pc);
IF pc # 0 THEN
i := 0; WHILE (i < LEN(types)) & (i < nofElements) & (types[i].pc # pc) DO INC(i) END;
IF (i < nofElements) THEN
INC(types[i].count);
INC(types[i].size, block.size);
ELSIF (i = nofElements) & (i < LEN(types)) THEN
types[i].ptag := 0;
types[i].count := 1;
types[i].size := block.size;
types[i].type := type;
types[i].pc := pc;
INC(nofElements)
END;
END;
END AddByPC;
PROCEDURE AddByType(type: SHORTINT);
VAR tag: SYSTEM.ADDRESS; i: LONGINT;
BEGIN
SYSTEM.GET(block.dataAdr + Heaps.TypeDescOffset, tag);
i := 0; WHILE (i < LEN(types)) & (i < nofElements) & (types[i].ptag # tag) DO INC(i) END;
IF (i < nofElements) THEN
INC(types[i].count);
INC(types[i].size, block.size);
ELSIF (i = nofElements) & (i < LEN(types)) THEN
types[i].ptag := tag;
types[i].count := 1;
types[i].size := block.size;
types[i].type := type;
types[i].pc := 0;
INC(nofElements)
END;
END AddByType;
BEGIN
INC(nofHeapBlocks); INC(sizeHeapBlocks, block.size);
IF (block IS Heaps.RecordBlock) OR (block IS Heaps.ProtRecBlock) OR (block IS Heaps.ArrayBlock) THEN
IF (block IS Heaps.ProtRecBlock) THEN
type := ProtRecBlock;
INC(nofProtRecBlocks); INC(sizeProtRecBlocks, block.size);
ELSIF (block IS Heaps.RecordBlock) THEN
type := RecordBlock;
INC(nofRecordBlocks); INC(sizeRecordBlocks, block.size);
ELSIF (block IS Heaps.ArrayBlock) THEN
type := ArrayBlock;
INC(nofArrayBlocks); INC(sizeArrayBlocks, block.size);
ELSE
HALT(99);
END;
IF byPC THEN
AddByPC(type)
ELSE
AddByType(type)
END;
ELSIF (block IS Heaps.SystemBlock) THEN
INC(nofSystemBlocks); INC(sizeSystemBlocks, block.size);
AddByPC(SystemBlock);
ELSIF (block IS Heaps.FreeBlock) THEN
INC(nofFreeBlocks); INC(sizeFreeBlocks, block.size);
END;
END Add;
PROCEDURE ShowBlocks(CONST mask : ARRAY OF CHAR; out : Streams.Writer);
VAR
module : Modules.Module; typedesc : Modules.TypeDesc;
size, totalSize: SYSTEM.SIZE;
startpc: SYSTEM.ADDRESS;
i, selected, total : LONGINT;
string : ARRAY 256 OF CHAR; copy: ARRAY 256 OF CHAR;
BEGIN
ASSERT(out # NIL);
size := 0; totalSize := 0;
selected := 0; total := 0;
FOR i := 0 TO nofElements-1 DO
INC(total, types[i].count);
module := NIL;
IF (types[i].pc # 0) THEN
module := Modules.ThisModuleByAdr(types[i].pc);
ELSIF (types[i].ptag # 0) THEN
Modules.ThisTypeByAdr(types[i].ptag, module, typedesc);
END;
IF (module # NIL) THEN
IF (types[i].ptag # 0) THEN
string := "";
COPY(module.name,copy);
Strings.AppendX(string, copy);
Strings.AppendX(string, ".");
COPY(typedesc.name,copy);
Strings.AppendX(string, copy);
ELSE
string := "";
COPY(module.name,copy);
Strings.AppendX(string, copy);
Strings.AppendX(string, ".");
Reflection.GetProcedureName(types[i].pc, copy,startpc);
Strings.AppendX(string, copy);
Strings.Append(string,":");
Strings.IntToStr(types[i].pc - startpc, copy);
Strings.Append(string,copy);
END;
IF Strings.Match(mask, string) THEN
CASE types[i].type OF
|RecordBlock: out.String("R ");
|ProtRecBlock: out.String("P ");
|ArrayBlock: out.String("A ");
|SystemBlock: out.String("S ");
ELSE
out.String("U ");
END;
INC(selected, types[i].count);
out.Int(types[i].count, 8); out.Char(" ");
INC(size, types[i].size);
out.Int(types[i].size DIV types[i].count, 6); out.String("B ");
out.Int(types[i].size, 10); out.String("B ");
out.String(string);
out.String(" (total ");
WriteB(types[i].size, out); out.String(")"); out.Ln
END;
END;
END;
out.Ln;
IF (selected # total) THEN
out.String("Selected "); out.Int(selected, 1); out.String(" of ");
out.Int(total, 1); out.String(" dynamic records of ");
out.Int(nofElements, 1); out.String(" unique types (total size : ");
WriteB(size, out); out.String(" of "); WriteB(totalSize, out); out.String(")");
out.Ln;
ELSE
out.Int(total, 1); out.String(" dynamic records of ");
out.Int(nofElements, 1); out.String(" unique types found");
out.String(" (total size : "); WriteB(sizeHeapBlocks, out); out.String(")");
out.Ln;
END;
END ShowBlocks;
PROCEDURE Show(out : Streams.Writer; CONST mask : ARRAY OF CHAR; sortMode : LONGINT; byPC: BOOLEAN);
VAR nofUsedBlocks, sizeUsedBlocks : LONGINT;
PROCEDURE ShowBlock(CONST name : ARRAY OF CHAR; nofBlocks: LONGINT; size: SYSTEM.SIZE; totalNofBlocks: LONGINT; totalSize : SYSTEM.SIZE; out : Streams.Writer);
BEGIN
out.Int(nofBlocks, 8); out.Char(" "); ShowPercent(nofBlocks, totalNofBlocks, out); out.Char(" ");
out.String(name);
out.String(" ("); WriteB(size, out); out.String(", "); ShowPercent(size, totalSize, out); out.String(")");
out.Ln;
END ShowBlock;
PROCEDURE ShowPercent(cur, max : SYSTEM.SIZE; out : Streams.Writer);
VAR percent : LONGINT;
BEGIN
IF (max > 0) THEN
percent := ENTIER(100 * (cur / max) + 0.5);
ELSE
percent := 0;
END;
IF (percent < 10) THEN out.String(" ");
ELSIF (percent < 100) THEN out.Char(" ");
END;
out.Int(percent, 0); out.Char("%");
END ShowPercent;
BEGIN
ASSERT(out # NIL);
nofUsedBlocks := nofHeapBlocks - nofFreeBlocks;
sizeUsedBlocks := sizeHeapBlocks - sizeFreeBlocks;
out.Char(0EX);
ShowBlock("HeapBlocks", nofHeapBlocks, sizeHeapBlocks, nofHeapBlocks, sizeHeapBlocks, out);
ShowBlock("UsedBlocks", nofUsedBlocks, sizeUsedBlocks, nofHeapBlocks, sizeHeapBlocks, out);
ShowBlock("FreeBlocks", nofFreeBlocks, sizeFreeBlocks, nofHeapBlocks, sizeHeapBlocks, out);
out.Ln;
ShowBlock("UsedBlocks", nofUsedBlocks, sizeUsedBlocks, nofUsedBlocks, sizeUsedBlocks, out);
ShowBlock("SystemBlocks", nofSystemBlocks, sizeSystemBlocks, nofUsedBlocks, sizeUsedBlocks, out);
ShowBlock("RecordBlocks", nofRecordBlocks, sizeRecordBlocks, nofUsedBlocks, sizeUsedBlocks, out);
ShowBlock("ProtRectBlocks", nofProtRecBlocks, sizeProtRecBlocks, nofUsedBlocks, sizeUsedBlocks, out);
ShowBlock("ArrayBlocks", nofArrayBlocks, sizeArrayBlocks, nofUsedBlocks, sizeUsedBlocks, out);
IF (mask # "") THEN
out.Ln;
IF (sortMode = SortByCount) OR (sortMode = SortBySize) OR (sortMode = SortByTotalSize) OR (sortMode = SortByName) THEN
SortBy(sortMode);
END;
ShowBlocks(mask, out);
END;
out.Char(0FX);
END Show;
END Analyzer;
VAR
currentMarkValueAddress : SYSTEM.ADDRESS;
PROCEDURE WriteB(b : SYSTEM.SIZE; out : Streams.Writer);
VAR shift : LONGINT; suffix : ARRAY 2 OF CHAR;
BEGIN
IF b < 100*1024 THEN suffix := ""; shift := 0
ELSIF b < 100*1024*1024 THEN suffix := "K"; shift := -10
ELSE suffix := "M"; shift := -20
END;
IF b # ASH(ASH(b, shift), -shift) THEN out.Char("~") END;
out.Int(ASH(b, shift), 1);
IF TRUE THEN
out.String(suffix); out.Char("B")
ELSE
out.Char(" ");
out.String(suffix); out.String("byte");
IF b # 1 THEN out.Char("s") END
END
END WriteB;
PROCEDURE ModuleDetails*(context : Commands.Context);
VAR
m : Modules.Module; i, j, k: LONGINT;
p, procAdr: SYSTEM.ADDRESS;
adr : SYSTEM.ADDRESS;
modn : ARRAY 33 OF CHAR;
options : Options.Options;
BEGIN
NEW(options);
options.Add("d", "details", Options.Flag);
IF options.Parse(context.arg, context.error) THEN
context.arg.SkipWhitespace; context.arg.String(modn);
m := Modules.root;
WHILE (m # NIL) & (m.name # modn) DO m := m.next END;
IF m # NIL THEN
context.out.String(m.name);
context.out.String(" refcnt = "); context.out.Int(m.refcnt, 1);
context.out.String(" sb ="); context.out.Hex(m.sb, 9);
context.out.String(" dataSize = "); context.out.Int(LEN(m.data), 1);
context.out.String(" staticTdSize = "); context.out.Int(LEN(m.staticTypeDescs), 1);
context.out.String(" codeSize = "); context.out.Int(LEN(m.code), 1);
context.out.String(" refSize = "); context.out.Int(LEN(m.refs), 1);
context.out.String(" entries = "); context.out.Int(LEN(m.entry), 1);
context.out.String(" commands = "); context.out.Int(LEN(m.command), 1);
context.out.String(" modules = "); context.out.Int(LEN(m.module), 1);
context.out.String(" types = "); context.out.Int(LEN(m.typeInfo), 1);
context.out.String(" pointers = "); context.out.Int(LEN(m.ptrAdr), 1);
context.out.Ln; context.out.String(" ptrAdr:");
FOR i := 0 TO LEN(m.ptrAdr)-1 DO
context.out.Char(" "); context.out.Int(m.ptrAdr[i]-m.sb, 1)
END;
context.out.Ln;
IF options.GetFlag("details") THEN
context.out.String("Pointer Details: ");
IF (m.ptrAdr # NIL) THEN
context.out.Ln;
FOR i := 0 TO LEN(m.ptrAdr) - 1 DO
context.out.Int(i, 0); context.out.String(": ");
context.out.Address(m.ptrAdr[i]); context.out.String(" -> ");
SYSTEM.GET(m.ptrAdr[i], adr);
context.out.Address(adr);
context.out.Ln;
END;
ELSE
context.out.String("none"); context.out.Ln;
END;
END;
FOR i := 0 TO LEN(m.typeInfo) - 1 DO
context.out.Ln; context.out.String(" type:");
context.out.Hex(m.typeInfo[i].tag, 9);
context.out.Char(" "); context.out.String(m.typeInfo[i].name);
context.out.Hex(SYSTEM.VAL(LONGINT, m.typeInfo[i].flags), 9);
context.out.Ln; context.out.String(" typedesc1:");
p := m.typeInfo[i].tag;
REPEAT
SYSTEM.GET(p, k);
IF ABS(k) <= 4096 THEN context.out.Char(" "); context.out.Int(k, 1)
ELSE context.out.Hex(k, 9)
END;
INC(p, AddressSize)
UNTIL k < -40000000H;
context.out.Ln; context.out.String(" typedescmths:");
p := SYSTEM.VAL(SYSTEM.ADDRESS, m.typeInfo[i].tag) + Modules.Mth0Ofs;
j := 0;
SYSTEM.GET(p, procAdr);
WHILE procAdr # Heaps.MethodEndMarker DO
context.out.Ln; context.out.Int(j, 3); context.out.Char(" ");
Reflection.WriteProc(context.out, procAdr);
DEC(p, AddressSize);
SYSTEM.GET(p, procAdr);
INC(j)
END
END;
context.out.Ln
END;
END;
END ModuleDetails;
PROCEDURE ModulePC*(context : Commands.Context);
VAR pc : LONGINT;
BEGIN
context.arg.SkipWhitespace; context.arg.Int(pc, FALSE);
IF Modules.ThisModuleByAdr(pc) # NIL THEN
Reflection.WriteProc(context.out, pc);
ELSE
context.out.Hex(pc, 8); context.out.String(" not found")
END;
context.out.Ln;
END ModulePC;
PROCEDURE AllObjects*(context : Commands.Context);
VAR
options : Options.Options; sortMode : LONGINT;
analyzer : Analyzer;
memBlock {UNTRACED}: Machine.MemoryBlock;
heapBlock : Heaps.HeapBlock;
p : SYSTEM.ADDRESS;
mask : ARRAY 128 OF CHAR;
BEGIN
NEW(options);
options.Add("s", "sort", Options.Integer);
options.Add(0X, "pc", Options.Flag);
IF options.Parse(context.arg, context.error) THEN
IF ~options.GetInteger("sort", sortMode) THEN sortMode := SortNone; END;
context.arg.SkipWhitespace; context.arg.String(mask);
NEW(analyzer, MaxNofTypes);
Machine.Acquire(Machine.Heaps);
memBlock := Machine.memBlockHead;
WHILE memBlock # NIL DO
p := memBlock.beginBlockAdr;
WHILE p # memBlock.endBlockAdr DO
heapBlock := SYSTEM.VAL(Heaps.HeapBlock, p + Heaps.BlockHeaderSize);
analyzer.Add(heapBlock, options.GetFlag("pc"));
p := p + heapBlock.size
END;
memBlock := memBlock.next
END;
Machine.Release(Machine.Heaps);
analyzer.Show(context.out, mask, sortMode, options.GetFlag("pc"));
END;
END AllObjects;
PROCEDURE TraceModule*(context : Commands.Context);
VAR
options : Options.Options; sortMode : LONGINT;
analyzer : Analyzer;
mask : ARRAY 128 OF CHAR;
moduleName : Modules.Name; module : Modules.Module;
BEGIN
NEW(options);
options.Add("s", "sort", Options.Integer);
IF options.Parse(context.arg, context.error) THEN
IF ~options.GetInteger("sort", sortMode) THEN sortMode := SortNone; END;
context.arg.SkipWhitespace; context.arg.String(moduleName);
context.arg.SkipWhitespace; context.arg.String(mask);
module := Modules.ModuleByName(moduleName);
IF (module # NIL) THEN
NEW(analyzer, MaxNofTypes);
Machine.Acquire(Machine.Heaps);
IncrementCurrentMarkValue;
module.FindRoots;
AnalyzeMarkedBlocks(analyzer);
Machine.Release(Machine.Heaps);
context.out.String("Heap block referenced by module "); context.out.String(moduleName); context.out.Char(":");
context.out.Ln;
analyzer.Show(context.out, mask, sortMode, FALSE);
ELSE
context.error.String("Module "); context.error.String(moduleName); context.error.String(" is not loaded."); context.error.Ln;
END;
END;
END TraceModule;
PROCEDURE TraceReference*(context : Commands.Context);
VAR
options : Options.Options; sortMode : LONGINT;
analyzer : Analyzer; address : SYSTEM.ADDRESS;
module : Modules.Module; variable : Reflection.Variable;
mask, modVar : ARRAY 256 OF CHAR; array : Strings.StringArray;
varName : ARRAY 64 OF CHAR;
BEGIN
NEW(options);
options.Add("s", "sort", Options.Integer);
IF options.Parse(context.arg, context.error) THEN
IF ~options.GetInteger("sort", sortMode) THEN sortMode := SortNone; END;
context.arg.SkipWhitespace; context.arg.String(modVar);
context.arg.SkipWhitespace; context.arg.String(mask);
array := Strings.Split(modVar, ".");
IF (LEN(array) = 2) THEN
module := Modules.ModuleByName(array[0]^);
IF (module # NIL) THEN
COPY(array[1]^, varName);
IF Reflection.FindVar(module, varName, variable) THEN
IF (variable.type = 13) OR (variable.type = 29) THEN
NEW(analyzer, MaxNofTypes);
context.out.String("Heap blocks reference by variable "); context.out.String(modVar);
context.out.Char(":"); context.out.Ln;
IF (variable.adr # 0) THEN
SYSTEM.GET(variable.adr, address);
MarkReference(analyzer, SYSTEM.VAL(ANY, address));
analyzer.Show(context.out, mask, sortMode, FALSE);
END;
ELSE
context.error.String("Variable is not a pointer"); context.error.Ln;
END;
ELSE
context.error.String("Variable "); context.error.String(array[1]^); context.error.String(" not found");
context.error.Ln;
END;
ELSE
context.error.String("Module "); context.error.String(array[0]^); context.error.String(" not found");
context.error.Ln;
END;
ELSE
context.error.String("Expected ModuleName.VariableName parameter"); context.error.Ln;
END;
END;
END TraceReference;
PROCEDURE MarkReference(analyzer : Analyzer; ref : ANY);
BEGIN
ASSERT(analyzer # NIL);
Machine.Acquire(Machine.Heaps);
IncrementCurrentMarkValue;
Heaps.Mark(ref);
AnalyzeMarkedBlocks(analyzer);
Machine.Release(Machine.Heaps);
END MarkReference;
PROCEDURE TraceProcessID*(context : Commands.Context);
VAR
options : Options.Options; sortMode : LONGINT;
analyzer : Analyzer;
process : Objects.Process;
processID : LONGINT; mask : ARRAY 256 OF CHAR;
BEGIN
NEW(options);
options.Add("s", "sort", Options.Integer);
IF options.Parse(context.arg, context.error) THEN
IF ~options.GetInteger("sort", sortMode) THEN sortMode := SortNone; END;
IF context.arg.GetInteger(processID, FALSE) THEN
context.arg.SkipWhitespace; context.arg.String(mask);
process := FindProcessByID(processID);
IF (process # NIL) THEN
NEW(analyzer, MaxNofTypes);
Machine.Acquire(Machine.Heaps);
IncrementCurrentMarkValue;
process.FindRoots;
Heaps.CheckCandidates;
AnalyzeMarkedBlocks(analyzer);
Machine.Release(Machine.Heaps);
context.out.String("Heap blocks referenced by process ID = "); context.out.Int(processID, 0); context.out.Char(":");
context.out.Ln;
analyzer.Show(context.out, mask, sortMode, FALSE);
ELSE
context.error.String("Process ID = "); context.error.Int(processID, 0); context.error.String(" not found");
context.error.Ln;
END;
ELSE
context.error.String("Expected ProcessID parameter"); context.error.Ln;
END;
END;
END TraceProcessID;
PROCEDURE FindProcessByID(id : LONGINT) : Objects.Process;
VAR
memBlock {UNTRACED}: Machine.MemoryBlock;
heapBlock {UNTRACED}: Heaps.HeapBlock;
blockAdr, tag : SYSTEM.ADDRESS;
process : Objects.Process;
i : LONGINT;
BEGIN
i := 0;
Machine.Acquire(Machine.Heaps);
process := NIL;
memBlock := Machine.memBlockHead;
WHILE (memBlock # NIL) & (process = NIL) DO
blockAdr := memBlock.beginBlockAdr;
WHILE (blockAdr # memBlock.endBlockAdr) & (process = NIL) DO
heapBlock := SYSTEM.VAL(Heaps.HeapBlock, blockAdr + Heaps.BlockHeaderSize);
IF (heapBlock IS Heaps.RecordBlock) THEN
SYSTEM.GET(heapBlock.dataAdr + Heaps.TypeDescOffset, tag);
IF (tag = SYSTEM.TYPECODE(Objects.Process)) THEN
process := SYSTEM.VAL(Objects.Process, heapBlock.dataAdr);
IF (process.id # id) THEN process := NIL; END;
END;
END;
blockAdr := blockAdr + heapBlock.size
END;
memBlock := memBlock.next
END;
Machine.Release(Machine.Heaps);
RETURN process;
END FindProcessByID;
PROCEDURE AnalyzeMarkedBlocks(analyzer : Analyzer);
VAR
memBlock {UNTRACED}: Machine.MemoryBlock;
heapBlock : Heaps.HeapBlock;
currentMarkValue : LONGINT;
blockAdr : SYSTEM.ADDRESS;
mark : LONGINT;
BEGIN
ASSERT(analyzer # NIL);
currentMarkValue := GetCurrentMarkValue();
memBlock := Machine.memBlockHead;
WHILE memBlock # NIL DO
blockAdr := memBlock.beginBlockAdr;
WHILE blockAdr # memBlock.endBlockAdr DO
heapBlock := SYSTEM.VAL(Heaps.HeapBlock, blockAdr + Heaps.BlockHeaderSize);
mark := SYSTEM.GET32(blockAdr + Heaps.BlockHeaderSize);
IF (mark = currentMarkValue) THEN
analyzer.Add(heapBlock, FALSE);
SYSTEM.PUT32(blockAdr + Heaps.BlockHeaderSize, currentMarkValue - 1);
END;
blockAdr := blockAdr + heapBlock.size
END;
memBlock := memBlock.next
END;
SetCurrentMarkValue(currentMarkValue - 1);
END AnalyzeMarkedBlocks;
PROCEDURE WriteType(adr : LONGINT; out : Streams.Writer);
VAR m : Modules.Module; t : Modules.TypeDesc; name: ARRAY 256 OF CHAR;
BEGIN
Modules.ThisTypeByAdr(adr, m, t);
IF m # NIL THEN
out.String(m.name); out.Char(".");
IF (t # NIL) THEN
IF t.name = "" THEN out.String("TYPE") ELSE
COPY(t.name,name);
out.String(name) END
ELSE
out.String("NOTYPEDESC");
END;
ELSE
out.String("NIL")
END
END WriteType;
PROCEDURE GetName(adr: LONGINT; VAR name: ARRAY OF CHAR);
VAR m : Modules.Module; t : Modules.TypeDesc;
BEGIN
Modules.ThisTypeByAdr(adr, m, t);
name := "";
IF m # NIL THEN
COPY(m.name,name);
IF (t # NIL) THEN
Strings.Append(name,".");
Strings.Append(name,t.name);
END;
END;
END GetName;
PROCEDURE GetCurrentMarkValue() : LONGINT;
BEGIN
RETURN SYSTEM.GET32(currentMarkValueAddress);
END GetCurrentMarkValue;
PROCEDURE SetCurrentMarkValue(value : LONGINT);
BEGIN
SYSTEM.PUT32(currentMarkValueAddress, value);
END SetCurrentMarkValue;
PROCEDURE IncrementCurrentMarkValue;
BEGIN
SetCurrentMarkValue(GetCurrentMarkValue() + 1);
END IncrementCurrentMarkValue;
PROCEDURE GetCurrentMarkValueAddress() : SYSTEM.ADDRESS;
VAR address : SYSTEM.ADDRESS; module : Modules.Module; variable : Reflection.Variable;
BEGIN
address := Heaps.NilVal;
module := Modules.ModuleByName("Heaps");
IF (module # NIL) THEN
IF Reflection.FindVar(module, "currentMarkValue", variable) THEN
ASSERT(variable.n = 1);
ASSERT(variable.type = 6);
address := variable.adr;
END;
END;
RETURN address;
END GetCurrentMarkValueAddress;
BEGIN
currentMarkValueAddress := GetCurrentMarkValueAddress();
ASSERT(currentMarkValueAddress # Heaps.NilVal);
END Info.
SystemTools.Free Info ~
Info.AllObjects ~
Info.AllObjects * ~
Info.AllObjects --sort=0 * ~
Info.AllObjects --sort=1 * ~
Info.AllObjects --sort=2 * ~
Info.TraceModule PET ~
Info.TraceModule Info ~
Info.TraceModule Info * ~
Info.TraceReference HotKeys.hotkeys ~
Info.TraceReference HotKeys.hotkeys * ~
Info.TraceProcessID 7180 * ~
Info.ModuleDetails -d Modules ~
SystemTools.CollectGarbage ~
Compiler.Compile --symbolFilePrefix=/temp/objEO/ --objectFilePrefix=/temp/objEO/ Info.Mod ~