language-Modula2-0.1: examples/Dipl/M2/MEMORY.MOD
IMPLEMENTATION MODULE Memory;
FROM Lib IMPORT AddAddr, DecAddr, IncAddr, SubAddr, Dos;
FROM SYSTEM IMPORT ADDRESS, BYTE, TSIZE, Registers;
FROM IO IMPORT WrStr, WrLn;
CONST
MaxMarkers=200;
MinParagraph=400H;
MaxParagraph=0A000H;
MinBitMap=MinParagraph DIV 16;
MaxBitMap=MaxParagraph DIV 16;
MaxBlockSize=1025;
VAR
markers:ARRAY [1..MaxMarkers] OF PROC;
lastMarker:[0..MaxMarkers];
bitMap:ARRAY [MinBitMap..MaxBitMap] OF BITSET;
HeapTop,HeapBottom:CARDINAL;
sizes:ARRAY [0..MaxBlockSize+1] OF
RECORD
paragraph:CARDINAL;
previous,next:[0..MaxBlockSize+1]
END;
largestBlock:[0..MaxBlockSize];
block1,length1:CARDINAL;
PROCEDURE FatalError(text:ARRAY OF CHAR);
BEGIN
WrLn;
WrStr('Greska u garbage collector modulu!');
WrLn;
WrStr(text);
HALT
END FatalError;
PROCEDURE AddMarker(m:PROC);
BEGIN
IF lastMarker<MaxMarkers THEN
INC(lastMarker);
markers[lastMarker]:=m
ELSE
FatalError('Prekoracen maximalan broj markera potrebnih celija u HEAPu!')
END
END AddMarker;
PROCEDURE DropMarker;
BEGIN
IF lastMarker>0 THEN
DEC(lastMarker)
ELSE
FatalError('Malo previse brisanja markera potrebnih celija u HEAPu.')
END
END DropMarker;
PROCEDURE MarkNeeded(VAR addr:ADDRESS; length:CARDINAL; VAR discovery:BOOLEAN);
VAR
paragraph:CARDINAL;
BEGIN
paragraph:=Seg(addr^);
IF Ofs(addr^)#0 THEN
paragraph:=paragraph + Ofs(addr^) DIV 16;
length:=length + Ofs(addr^) MOD 16
END;
length:=(length+15) DIV 16;
IF paragraph>=HeapBottom THEN
discovery:=FALSE;
IF paragraph>HeapTop THEN
RETURN
END;
REPEAT
IF NOT (paragraph MOD 16 IN bitMap[paragraph DIV 16]) THEN
discovery:=TRUE;
INCL(bitMap[paragraph DIV 16],paragraph MOD 16)
END;
INC(paragraph);
DEC(length)
UNTIL length=0
ELSE
discovery:=TRUE
END
END MarkNeeded;
(*#check(index => off) *)
(*#check(range => off) *)
(*#check(overflow => off) *)
(*#check(stack => off) *)
(*#check(guard => off) *)
(*#check(nil_ptr => off) *)
PROCEDURE Collect;
VAR
i,blockSize,previous:CARDINAL;
BEGIN
FOR i:=HeapBottom DIV 16 TO HeapTop DIV 16 DO
bitMap[i]:=BITSET(0)
END;
FOR i:=1 TO lastMarker DO
markers[i]
END;
largestBlock:=0;
FOR i:=1 TO MaxBlockSize DO
sizes[i].paragraph:=0
END;
EXCL(bitMap[HeapBottom DIV 16],HeapBottom MOD 16);
INCL(bitMap[(HeapBottom+1) DIV 16],(HeapBottom+1) MOD 16);
i:=HeapTop-1;
LOOP
WHILE i MOD 16 IN bitMap[i DIV 16] DO
DEC(i)
END;
IF i=HeapBottom THEN
EXIT
END;
blockSize:=0;
REPEAT
INC(blockSize);
DEC(i);
UNTIL i MOD 16 IN bitMap[i DIV 16];
IF blockSize>largestBlock THEN
IF blockSize>MaxBlockSize THEN
INC(i,blockSize-MaxBlockSize);
blockSize:=MaxBlockSize
END;
largestBlock:=blockSize
END;
[i+1:0]^:=sizes[blockSize].paragraph;
sizes[blockSize].paragraph:=i+1
END;
IF largestBlock=0 THEN
FatalError( 'Heap je definitivno prepunjen. Zaboravi na taj algoritam!' )
END;
previous:=0;
FOR blockSize:=1 TO largestBlock DO
IF sizes[blockSize].paragraph#0 THEN
sizes[blockSize].previous:=previous;
sizes[previous].next:=blockSize;
previous:=blockSize
END
END;
sizes[largestBlock].next:=MaxBlockSize+1;
length1:=0
END Collect;
PROCEDURE ALLOCATE(VAR ptr:ADDRESS; length:CARDINAL);
VAR
original:CARDINAL;
BEGIN
IF length<=16 THEN
IF sizes[1].paragraph#0 THEN
ptr:=[sizes[1].paragraph:0];
sizes[1].paragraph:=ptr^;
IF sizes[1].paragraph=0 THEN
sizes[0].next:=sizes[1].next;
sizes[sizes[1].next].previous:=0
END
ELSE
IF length1=0 THEN
length1:=sizes[0].next;
IF length1>MaxBlockSize THEN
Collect;
ALLOCATE(ptr,length);
RETURN
END;
block1:=sizes[length1].paragraph;
sizes[length1].paragraph:=[block1:0]^;
IF sizes[length1].paragraph=0 THEN
sizes[0].next:=sizes[length1].next;
sizes[sizes[length1].next].previous:=0
END
END;
ptr:=[block1:0];
INC(block1);
DEC(length1)
END
ELSE
length:=(length+15) DIV 16;
original:=length;
IF sizes[length].paragraph=0 THEN
length:=0;
REPEAT
length:=sizes[length].next
UNTIL length>=original;
IF length>MaxBlockSize THEN
Collect;
IF original>largestBlock THEN
FatalError( 'Heap je definitivno prepunjen. Zaboravi na taj algoritam!' )
END;
ALLOCATE(ptr,original*16);
RETURN
END
END;
WITH sizes[length] DO
IF length#original THEN
[paragraph+original:0]^:=sizes[length-original].paragraph;
sizes[length-original].paragraph:=paragraph+original;
IF [paragraph+original:0]^=WORD(0) THEN
sizes[previous].next:=length-original;
sizes[length-original].previous:=previous;
previous:=length-original;
sizes[length-original].next:=length
END
END;
ptr:=[paragraph:0];
paragraph:=ptr^;
IF paragraph=0 THEN
sizes[previous].next:=next;
sizes[next].previous:=previous
END
END
END
END ALLOCATE;
VAR
r:Registers;
BEGIN
r.AH:=48H;
r.BX:=0FFFFH;
Dos(r);
r.AH:=48H;
Dos(r);
HeapBottom:=r.AX;
HeapTop:=r.AX+r.BX-1;
lastMarker:=0;
Collect
END Memory.