|
@@ -13,6 +13,7 @@ MODULE Heaps; (** AUTHOR "pjm/Luc Bläser/U. Glavitsch (ug)"; PURPOSE "Heap mana
|
|
|
IMPORT Runtime (* enforce import order *), SYSTEM, Trace, Machine;
|
|
|
|
|
|
CONST
|
|
|
+
|
|
|
Paranoid = TRUE; (* if paranoid =true, then during mark phase the GC can accept spurious pointers but reports them
|
|
|
paranoid = false expects correct metadata and correct settings of untraced variables
|
|
|
moreover, it should improve GC mark speed *)
|
|
@@ -24,7 +25,7 @@ CONST
|
|
|
AddressSize = SIZEOF(ADDRESS);
|
|
|
|
|
|
MaxTries = 16; (* max number of times to try and allocate memory, before trapping *)
|
|
|
- Unmarked = -1; (* mark value of free blocks *)
|
|
|
+ Unmarked = 0; (* mark value of free blocks *)
|
|
|
BlockSize* = 32; (* power of two, <= 32 for RegisterCandidates *)
|
|
|
ArrayAlignment = 8; (* first array element of ArrayBlock and first data element of SystemBlock must be aligned to 0 MOD ArrayAlignment *)
|
|
|
BlockHeaderSize* = 2 * AddressSize;
|
|
@@ -51,6 +52,15 @@ CONST
|
|
|
HeuristicStackInspectionGC* = 0;
|
|
|
MetaDataForStackGC* = 1;
|
|
|
|
|
|
+ (* generations *)
|
|
|
+ Old = 1;
|
|
|
+ Young = 0;
|
|
|
+ GenerationMask = 2;
|
|
|
+ (* card set for generational GC *)
|
|
|
+ CardSize = 4096;
|
|
|
+ SetSize=SIZEOF(SET) * 8;
|
|
|
+
|
|
|
+
|
|
|
TYPE
|
|
|
RootObject* = OBJECT (* ref. Linker0 *)
|
|
|
VAR nextRoot: RootObject; (* for linking root objects during GC *)
|
|
@@ -86,8 +96,21 @@ TYPE
|
|
|
dataAdr-: ADDRESS;
|
|
|
size-: SIZE;
|
|
|
nextMark {UNTRACED}: HeapBlock;
|
|
|
- (*generation-: LONGINT;*)
|
|
|
END;
|
|
|
+
|
|
|
+ (* mechanism of the generational garbage collector
|
|
|
+
|
|
|
+ - newly created objects belong to the young generation
|
|
|
+ - a new link from old to young must be entered in a list (an array), when the list is (nearly) full a GC cycle must be run
|
|
|
+ - any other link, from young to young or from rootset to young does not require action
|
|
|
+
|
|
|
+ - a gc cycle dealing with the young objects traverses the root set and the set of young pointers
|
|
|
+ - older objects are not marked or traversed
|
|
|
+ - when sweeping only unmarked objects not older than the sweep generation can be freed
|
|
|
+
|
|
|
+ - objects that survive a collection are considered old and are always moved to the tenured objects
|
|
|
+
|
|
|
+ *)
|
|
|
|
|
|
FreeBlock* = POINTER TO FreeBlockDesc;
|
|
|
FreeBlockU = POINTER {UNSAFE} TO FreeBlockDesc;
|
|
@@ -205,6 +228,8 @@ VAR
|
|
|
GC*: PROCEDURE; (** activate the garbage collector *)
|
|
|
initBlock {UNTRACED}: ANY; (* anchor for init calls *)
|
|
|
currentMarkValue: LONGINT; (* all objects that have this value in their mark field are still used - initial value filled in by linker *)
|
|
|
+ generationMarkValues : ARRAY 2 OF LONGINT; (* mark values of the generations *)
|
|
|
+ currentGeneration: LONGINT; (* current global generation state *)
|
|
|
sweepMarkValue: LONGINT; (* most recent mark value *)
|
|
|
sweepBlockAdr: ADDRESS; (* where to resume sweeping *)
|
|
|
sweepMemBlock {UNTRACED}: Machine.MemoryBlock; (* where to resume sweeping *)
|
|
@@ -294,7 +319,102 @@ BEGIN
|
|
|
RETURN heapBlock;
|
|
|
END ExtractFromMarkList;
|
|
|
|
|
|
-PROCEDURE Inspect(block {UNTRACED}: ANY);
|
|
|
+VAR
|
|
|
+ cardSet: ARRAY 0x100000000 DIV SetSize DIV CardSize OF SET; (* 1 k blocks *)
|
|
|
+
|
|
|
+PROCEDURE ShowCards*;
|
|
|
+VAR i: LONGINT;
|
|
|
+BEGIN
|
|
|
+ FOR i := 0 TO LEN(cardSet)-1 DO
|
|
|
+ IF cardSet[i] # {} THEN
|
|
|
+ Trace.Int(i,1); Trace.Set(cardSet[i]); Trace.Ln;
|
|
|
+ END;
|
|
|
+ END;
|
|
|
+END ShowCards;
|
|
|
+
|
|
|
+PROCEDURE ClearCardSet;
|
|
|
+VAR i: LONGINT;
|
|
|
+BEGIN
|
|
|
+ FOR i := 0 TO LEN(cardSet)-1 DO
|
|
|
+ cardSet[i] := {};
|
|
|
+ END;
|
|
|
+END ClearCardSet;
|
|
|
+
|
|
|
+(* lock-free entry into card-set *)
|
|
|
+PROCEDURE EnterInCardSet(adr: ADDRESS);
|
|
|
+VAR value: SET;
|
|
|
+BEGIN
|
|
|
+ adr := adr DIV CardSize;
|
|
|
+ IF adr MOD SetSize IN CAS(cardSet[adr DIV SetSize],{},{}) THEN
|
|
|
+ RETURN
|
|
|
+ ELSE
|
|
|
+ LOOP
|
|
|
+ value := CAS (cardSet[adr DIV SetSize], {},{});
|
|
|
+ IF CAS (cardSet[adr DIV SetSize], value, value + {adr MOD SetSize}) = value THEN EXIT END;
|
|
|
+ (*CPU.Backoff;*)
|
|
|
+ END;
|
|
|
+ END;
|
|
|
+END EnterInCardSet;
|
|
|
+
|
|
|
+PROCEDURE CheckAssignment*(dest, src: DataBlockU);
|
|
|
+BEGIN
|
|
|
+ IF (src # NIL) & (src.heapBlock # NIL) & (src.heapBlock.mark MOD GenerationMask = Young) THEN
|
|
|
+ EnterInCardSet(dest);
|
|
|
+ END;
|
|
|
+END CheckAssignment;
|
|
|
+
|
|
|
+(* Sweep phase *)
|
|
|
+PROCEDURE SweepCardSet();
|
|
|
+VAR
|
|
|
+ block : HeapBlockU ;
|
|
|
+ blockMark, blockGeneration: LONGINT;
|
|
|
+ memBlock {UNTRACED} : Machine.MemoryBlock;
|
|
|
+ blockAdr,a1,a2: ADDRESS;
|
|
|
+ count,count2,count3: LONGINT;
|
|
|
+ orgBlock: HeapBlockU;
|
|
|
+ mark: BOOLEAN;
|
|
|
+ time1, time2: HUGEINT;
|
|
|
+BEGIN {UNCHECKED}
|
|
|
+ (* blocks in the bootheap are not found by the sweep card set! *)
|
|
|
+ time1 := Machine.GetTimer ();
|
|
|
+ count := 0; count2 := 0;
|
|
|
+ memBlock := Machine.memBlockHead;
|
|
|
+ WHILE (memBlock # NIL) DO
|
|
|
+ blockAdr := memBlock.beginBlockAdr;
|
|
|
+ WHILE (blockAdr < memBlock.endBlockAdr) DO
|
|
|
+ block := blockAdr + BlockHeaderSize;
|
|
|
+ a1 := blockAdr DIV CardSize;
|
|
|
+ a2 := (blockAdr + block.size -1) DIV CardSize;
|
|
|
+ mark := FALSE;
|
|
|
+ REPEAT
|
|
|
+ mark := a1 MOD SetSize IN cardSet[a1 DIV SetSize];
|
|
|
+ INC(a1);
|
|
|
+ UNTIL mark OR (a1 > a2);
|
|
|
+
|
|
|
+ IF mark THEN
|
|
|
+ IF (block.mark MOD GenerationMask = Old) & (block.mark >= generationMarkValues[Old]) THEN
|
|
|
+ orgBlock := block.dataAdr;
|
|
|
+ ASSERT(orgBlock # NIL);
|
|
|
+ Inspect(orgBlock, Old);
|
|
|
+ INC(count);
|
|
|
+ ELSE INC(count2);
|
|
|
+ END;
|
|
|
+ ELSE
|
|
|
+ INC(count3);
|
|
|
+ END;
|
|
|
+ blockAdr := blockAdr + block.size
|
|
|
+ END;
|
|
|
+ memBlock := memBlock.next;
|
|
|
+ END;
|
|
|
+ time2 := Machine.GetTimer ();
|
|
|
+ (*
|
|
|
+ TRACE(LONGINT((time2-time1) DIV (1024*1024)));
|
|
|
+ TRACE(count,count2,count3);
|
|
|
+ *)
|
|
|
+END SweepCardSet;
|
|
|
+
|
|
|
+
|
|
|
+PROCEDURE Inspect(block {UNTRACED}: ANY; generation: LONGINT);
|
|
|
VAR
|
|
|
heapBlock {UNTRACED}: HeapBlock;
|
|
|
rootObj{UNTRACED}: RootObject;
|
|
@@ -304,8 +424,9 @@ BEGIN
|
|
|
IF (block = NIL) OR Paranoid & ~CheckPointer(block) THEN RETURN END;
|
|
|
blockMeta := block;
|
|
|
heapBlock := blockMeta.heapBlock;
|
|
|
- IF (heapBlock = NIL) OR (heapBlock.mark >= currentMarkValue) THEN RETURN END;
|
|
|
- heapBlock.mark := currentMarkValue;
|
|
|
+ IF (heapBlock = NIL) OR (heapBlock.mark >= currentMarkValue) OR (heapBlock.mark MOD GenerationMask > generation) & ~((blockMeta.typeBlock#NIL) & (block IS RootObject)) THEN RETURN END;
|
|
|
+ (* blocks in the bootheap are not found by the sweep card set, thus the root objects must be traversed in all cases *)
|
|
|
+ heapBlock.mark := currentMarkValue + Old (* surviving objects age *);
|
|
|
IF Stats THEN INC(Nmarked) END;
|
|
|
IF (heapBlock IS RecordBlock) OR (heapBlock IS ProtRecBlock) OR (heapBlock IS ArrayBlock) THEN
|
|
|
IF block IS RootObject THEN
|
|
@@ -328,43 +449,36 @@ VAR orgBlock: ADDRESS; staticTypeBlock {UNTRACED}: StaticTypeBlock;
|
|
|
meta: POINTER {UNSAFE} TO RECORD staticTypeBlock {FICTIVE=TypeDescOffset}: StaticTypeBlock; last, current, first: ADDRESS END;
|
|
|
BEGIN{UNCHECKED} (* omit any range checks etc.*)
|
|
|
IF Stats THEN INC(Nmark) END;
|
|
|
- Inspect(p);
|
|
|
+ Inspect(p,currentGeneration);
|
|
|
orgHeapBlock := ExtractFromMarkList();
|
|
|
WHILE orgHeapBlock # NIL DO
|
|
|
orgBlock := orgHeapBlock.dataAdr;
|
|
|
meta := orgBlock;
|
|
|
staticTypeBlock := meta.staticTypeBlock;
|
|
|
- (*
|
|
|
- IF TraceInvalid THEN
|
|
|
- TRACE(orgBlock);
|
|
|
- IF staticTypeBlock # NIL THEN WriteType(staticTypeBlock); END
|
|
|
- END;
|
|
|
- *)
|
|
|
|
|
|
IF ~(orgHeapBlock IS ArrayBlock) THEN
|
|
|
FOR i := 0 TO LEN(staticTypeBlock.pointerOffsets) - 1 DO
|
|
|
b := orgBlock + staticTypeBlock.pointerOffsets[i];
|
|
|
- Inspect(b.p)
|
|
|
+ Inspect(b.p,currentGeneration)
|
|
|
END
|
|
|
ELSE
|
|
|
currentArrayElemAdr := meta.first;
|
|
|
|
|
|
lastArrayElemAdr := meta.first + meta.last * staticTypeBlock.recSize;
|
|
|
- IF currentArrayElemAdr > lastArrayElemAdr THEN HALT(100) END;
|
|
|
WHILE currentArrayElemAdr < lastArrayElemAdr DO
|
|
|
FOR i := 0 TO LEN(staticTypeBlock.pointerOffsets) - 1 DO
|
|
|
b := currentArrayElemAdr + staticTypeBlock.pointerOffsets[i];
|
|
|
- Inspect(b.p)
|
|
|
+ Inspect(b.p,currentGeneration)
|
|
|
END;
|
|
|
INC(currentArrayElemAdr, staticTypeBlock.recSize);
|
|
|
END
|
|
|
END;
|
|
|
IF orgHeapBlock IS ProtRecBlock THEN
|
|
|
protected := orgHeapBlock(ProtRecBlock);
|
|
|
- Inspect(protected.awaitingLock.head);
|
|
|
- Inspect(protected.awaitingCond.head);
|
|
|
- Inspect(protected.lockedBy);
|
|
|
- Inspect(protected.lock);
|
|
|
+ Inspect(protected.awaitingLock.head, currentGeneration);
|
|
|
+ Inspect(protected.awaitingCond.head, currentGeneration);
|
|
|
+ Inspect(protected.lockedBy, currentGeneration);
|
|
|
+ Inspect(protected.lock, currentGeneration);
|
|
|
END;
|
|
|
orgHeapBlock := ExtractFromMarkList();
|
|
|
END;
|
|
@@ -567,7 +681,7 @@ VAR
|
|
|
lastFreeBlockAdr: ADDRESS;
|
|
|
lastFreeBlockSize: ADDRESS;
|
|
|
block : HeapBlockU ; freeBlock, lastFreeBlock: FreeBlockU;
|
|
|
- blockMark: LONGINT; blockSize: SIZE;
|
|
|
+ blockMark, blockGeneration: LONGINT; blockSize: SIZE;
|
|
|
time1, time2: HUGEINT;
|
|
|
CONST FreeBlockHeaderSize = SIZEOF(FreeBlockDesc) + BlockHeaderSize;
|
|
|
CONST StrongChecks = FALSE;
|
|
@@ -589,8 +703,9 @@ BEGIN{UNCHECKED}
|
|
|
WHILE (sweepBlockAdr < sweepMemBlock.endBlockAdr) DO
|
|
|
block := sweepBlockAdr + BlockHeaderSize;
|
|
|
blockMark := block.mark; (* cache these values since they may be overwritten during concatenation *)
|
|
|
+ blockGeneration := block.mark MOD GenerationMask;
|
|
|
blockSize := block.size;
|
|
|
- IF (blockMark < sweepMarkValue) THEN
|
|
|
+ IF (blockMark < generationMarkValues[blockGeneration]) THEN
|
|
|
IF (block.typeDesc # freeBlockTag) THEN
|
|
|
Machine.Fill32(sweepBlockAdr + FreeBlockHeaderSize, blockSize - FreeBlockHeaderSize, DebugValue);
|
|
|
END;
|
|
@@ -609,7 +724,8 @@ BEGIN{UNCHECKED}
|
|
|
ELSIF StrongChecks THEN
|
|
|
ASSERT(block.typeDesc = freeBlockTag);
|
|
|
END;
|
|
|
- IF (lastFreeBlockAdr # NIL) & ((blockMark >= sweepMarkValue) OR (lastFreeBlockSize >= size) OR (sweepBlockAdr + blockSize = sweepMemBlock.endBlockAdr) )
|
|
|
+
|
|
|
+ IF (lastFreeBlockAdr # NIL) & ((blockMark >= (* sweepMarkValue *) generationMarkValues[blockGeneration]) OR (lastFreeBlockSize >= size) OR (sweepBlockAdr + blockSize = sweepMemBlock.endBlockAdr) )
|
|
|
THEN (* no further merging is possible *)
|
|
|
IF StrongChecks THEN ASSERT(sweepBlockAdr + blockSize <= sweepMemBlock.endBlockAdr) END;
|
|
|
IF lastFreeBlockSize >= size THEN (* block found - may be too big *)
|
|
@@ -848,7 +964,7 @@ BEGIN
|
|
|
n := checkRoot;
|
|
|
WHILE n # NIL DO (* move unmarked checked objects to finalize list *)
|
|
|
SYSTEM.GET(SYSTEM.VAL(ADDRESS, n.objWeak) + HeapBlockOffset, heapBlock);
|
|
|
- IF heapBlock.mark < currentMarkValue THEN
|
|
|
+ IF (heapBlock.mark < generationMarkValues[heapBlock.mark MOD GenerationMask]) THEN
|
|
|
IF n = checkRoot THEN checkRoot := n.nextFin ELSE p.nextFin := n.nextFin END;
|
|
|
n.objStrong := n.objWeak; (* anchor the object for finalization *)
|
|
|
n.finalizerStrong := n.finalizer; (* anchor the finalizer for finalization *)
|
|
@@ -947,6 +1063,7 @@ VAR
|
|
|
obj: RootObject;
|
|
|
time1, time2: HUGEINT;
|
|
|
f: FreeBlock;
|
|
|
+ i: LONGINT;
|
|
|
BEGIN
|
|
|
(* do never use any low level locks as the garbage collector process has a very high priority and may thus be blocked by lower level processes -> potential deadlock *)
|
|
|
(*!
|
|
@@ -961,7 +1078,18 @@ BEGIN
|
|
|
END;
|
|
|
numCandidates := 0;
|
|
|
rootList := NIL;
|
|
|
- INC(currentMarkValue);
|
|
|
+ INC(currentMarkValue, GenerationMask);
|
|
|
+
|
|
|
+ FOR i := 0 TO currentGeneration DO
|
|
|
+ generationMarkValues[i] := currentMarkValue;
|
|
|
+ END;
|
|
|
+ (* TRACE(currentGeneration); *)
|
|
|
+ IF currentGeneration = Young THEN
|
|
|
+ (* sweep and enter all old blocks containing old -> new pointers *)
|
|
|
+ SweepCardSet();
|
|
|
+ END;
|
|
|
+ ClearCardSet();
|
|
|
+
|
|
|
AddRootObject(root);
|
|
|
|
|
|
IF GCType = HeuristicStackInspectionGC THEN
|
|
@@ -982,7 +1110,6 @@ BEGIN
|
|
|
UNTIL rootList = NIL;
|
|
|
|
|
|
ELSIF GCType = MetaDataForStackGC THEN
|
|
|
-
|
|
|
REPEAT
|
|
|
IF rootList # NIL THEN (* check root objects *)
|
|
|
REPEAT
|
|
@@ -1006,7 +1133,7 @@ BEGIN
|
|
|
INC(NgcCyclesAllRuns, NgcCyclesLastRun);
|
|
|
NgcCyclesMark := NgcCyclesLastRun
|
|
|
END;
|
|
|
-
|
|
|
+ (* TRACE(LONGINT((time2-time1) DIV (1024*1024))); *)
|
|
|
END;
|
|
|
|
|
|
IF EnableFreeLists THEN GetFreeBlock(MAX(LONGINT), f) END;
|
|
@@ -1063,6 +1190,8 @@ BEGIN
|
|
|
Machine.Release(Machine.Heaps);
|
|
|
END LazySweepGC;
|
|
|
|
|
|
+VAR youngCounts: LONGINT;
|
|
|
+
|
|
|
(* initialize a free heap block *)
|
|
|
PROCEDURE InitFreeBlock(freeBlock: FreeBlockU; mark: LONGINT; dataAdr: ADDRESS; size: SIZE);
|
|
|
CONST FreeBlockHeaderSize = SIZEOF(FreeBlockDesc) + BlockHeaderSize;
|
|
@@ -1071,7 +1200,7 @@ BEGIN
|
|
|
freeBlock.typeDesc := freeBlockTag;
|
|
|
freeBlock.heapBlock := NIL;
|
|
|
(* initialize heap block fields *)
|
|
|
- freeBlock.mark := mark;
|
|
|
+ freeBlock.mark := mark + Young;
|
|
|
freeBlock.dataAdr := dataAdr;
|
|
|
freeBlock.size := size;
|
|
|
(* initialize free block fields *)
|
|
@@ -1096,7 +1225,7 @@ BEGIN
|
|
|
CheckPostGC;
|
|
|
try := 1;
|
|
|
p := NIL;
|
|
|
- IF (GC = NilGC) OR (throughput < 128*1024*1024) THEN
|
|
|
+ IF (GC = NilGC) OR (throughput < 64*1024*1024) THEN
|
|
|
GetFreeBlock(size, p);
|
|
|
IF (p=NIL) THEN (* try restart sweep for once *)
|
|
|
GetFreeBlock(size, p);
|
|
@@ -1107,12 +1236,30 @@ BEGIN
|
|
|
|
|
|
|
|
|
WHILE (p = NIL) & (try <= MaxTries) DO
|
|
|
+ IF currentGeneration = Young THEN INC(youngCounts) END;
|
|
|
+ IF youngCounts > 100 THEN
|
|
|
+ currentGeneration := Old;
|
|
|
+ END;
|
|
|
Machine.Release(Machine.Heaps); (* give up control *)
|
|
|
GC; (* try to free memory (other processes may also steal memory now) *)
|
|
|
Machine.Acquire(Machine.Heaps);
|
|
|
CheckPostGC;
|
|
|
sweepMemBlock := NIL;
|
|
|
GetFreeBlock(size, p);
|
|
|
+ IF (currentGeneration = Young) & (p=NIL) THEN
|
|
|
+ currentGeneration := Old;
|
|
|
+ Machine.Release(Machine.Heaps); (* give up control *)
|
|
|
+ GC; (* try to free memory (other processes may also steal memory now) *)
|
|
|
+ Machine.Acquire(Machine.Heaps);
|
|
|
+ CheckPostGC;
|
|
|
+ currentGeneration := Young;
|
|
|
+ sweepMemBlock := NIL;
|
|
|
+ GetFreeBlock(size, p);
|
|
|
+ END;
|
|
|
+ IF youngCounts > 100 THEN
|
|
|
+ currentGeneration := Young;
|
|
|
+ youngCounts := 0;
|
|
|
+ END;
|
|
|
IF p = NIL THEN
|
|
|
Machine.ExpandHeap(try, size, memBlock, beginHeapBlockAdr, endHeapBlockAdr); (* try to extend the heap *)
|
|
|
IF endHeapBlockAdr > beginHeapBlockAdr THEN
|
|
@@ -1179,7 +1326,7 @@ BEGIN
|
|
|
systemBlock.typeDesc := systemBlockTag;
|
|
|
dataBlock.typeDesc := NilVal;
|
|
|
dataBlock.heapBlock := systemBlock;
|
|
|
- systemBlock.mark := currentMarkValue;
|
|
|
+ systemBlock.mark := currentMarkValue + Young;
|
|
|
systemBlock.dataAdr := dataBlockAdr;
|
|
|
systemBlock.size := blockSize;
|
|
|
(*! disable realtime block handling for the time being
|
|
@@ -1229,7 +1376,7 @@ BEGIN
|
|
|
recordBlock.typeDesc := recordBlockTag;
|
|
|
dataBlock.typeDesc := tag;
|
|
|
dataBlock.heapBlock := recordBlockAdr;
|
|
|
- recordBlock.mark := currentMarkValue;
|
|
|
+ recordBlock.mark := currentMarkValue + Young;
|
|
|
recordBlock.dataAdr := dataBlockAdr;
|
|
|
recordBlock.size := blockSize;
|
|
|
|
|
@@ -1244,7 +1391,8 @@ BEGIN
|
|
|
|
|
|
SetPC(dataBlock);
|
|
|
p := dataBlock;
|
|
|
-
|
|
|
+ EnterInCardSet(ADDRESS OF p);
|
|
|
+
|
|
|
(* clear must be done inside lock to ensure all traced pointer fields are initialized to NIL *)
|
|
|
Machine.Fill32(dataBlockAdr, blockSize - SIZEOF(RecordBlockDesc) - 2 * BlockHeaderSize, 0); (* clear everything from dataBlockAdr until end of block *)
|
|
|
ELSE
|
|
@@ -1277,7 +1425,7 @@ BEGIN
|
|
|
protRecBlock.typeDesc := protRecBlockTag;
|
|
|
dataBlock.typeDesc := tag;
|
|
|
dataBlock.heapBlock := protRecBlockAdr;
|
|
|
- protRecBlock.mark := currentMarkValue;
|
|
|
+ protRecBlock.mark := currentMarkValue + Young;
|
|
|
protRecBlock.dataAdr := dataBlockAdr;
|
|
|
protRecBlock.size := blockSize;
|
|
|
(*! disable realtime block handling for the time being
|
|
@@ -1303,6 +1451,7 @@ BEGIN
|
|
|
|
|
|
SetPC(dataBlock);
|
|
|
p := dataBlock;
|
|
|
+ EnterInCardSet(ADDRESS OF p);
|
|
|
|
|
|
(* clear must be done inside lock to ensure all traced pointer fields are initialized to NIL *)
|
|
|
Machine.Fill32(dataBlockAdr, blockSize - SIZEOF(ProtRecBlockDesc) - 2 * BlockHeaderSize, 0); (* clear everything from dataBlockAdr to end of block *)
|
|
@@ -1354,7 +1503,7 @@ BEGIN
|
|
|
arrayBlock.typeDesc := arrayBlockTag;
|
|
|
dataBlock.typeDesc := elemType;
|
|
|
dataBlock.heapBlock := arrayBlock;
|
|
|
- arrayBlock.mark := currentMarkValue;
|
|
|
+ arrayBlock.mark := currentMarkValue + Young;
|
|
|
arrayBlock.dataAdr := dataBlockAdr;
|
|
|
arrayBlock.size := blockSize;
|
|
|
|
|
@@ -1378,6 +1527,7 @@ BEGIN
|
|
|
|
|
|
SetPC(dataBlock);
|
|
|
p := dataBlock;
|
|
|
+ EnterInCardSet(ADDRESS OF p);
|
|
|
ELSE
|
|
|
p := NIL
|
|
|
END;
|
|
@@ -1426,6 +1576,7 @@ VAR p: ANY; dim: SIZE;
|
|
|
SetSizes(p);
|
|
|
SetPC(p);
|
|
|
dest := p;
|
|
|
+ EnterInCardSet(ADDRESS OF dest);
|
|
|
END NewArray;
|
|
|
|
|
|
|
|
@@ -1513,21 +1664,31 @@ VAR assigns*: LONGINT;
|
|
|
|
|
|
PROCEDURE Assign*(VAR dest: ADDRESS; src: ADDRESS);
|
|
|
BEGIN
|
|
|
- (*TRACE(dest,src);*)
|
|
|
+ CheckAssignment(ADDRESS OF dest,src);
|
|
|
dest := src;
|
|
|
INC(assigns);
|
|
|
END Assign;
|
|
|
|
|
|
PROCEDURE AssignRecord*(dest: ADDRESS; tag: StaticTypeBlockU; src: ADDRESS);
|
|
|
+VAR i: LONGINT; sval: ADDRESS;
|
|
|
BEGIN
|
|
|
- (*TRACE(dest,tag.recSize,LEN(tag.pointerOffsets),src);*)
|
|
|
+ FOR i := 0 TO LEN(tag.pointerOffsets)-1 DO
|
|
|
+ SYSTEM.GET(src+tag.pointerOffsets[i], sval);
|
|
|
+ CheckAssignment(dest + tag.pointerOffsets[i], sval);
|
|
|
+ END;
|
|
|
SYSTEM.MOVE(src,dest,tag.recSize);
|
|
|
INC(assigns);
|
|
|
END AssignRecord;
|
|
|
|
|
|
PROCEDURE AssignArray*(dest: ADDRESS; tag: StaticTypeBlockU; numElems: SIZE; src: ADDRESS);
|
|
|
+VAR i, j: LONGINT; sval: ADDRESS;
|
|
|
BEGIN
|
|
|
- (*TRACE(dest,tag.recSize,LEN(tag.pointerOffsets),numElems,src);*)
|
|
|
+ FOR j := 0 TO LEN(tag.pointerOffsets)-1 DO
|
|
|
+ FOR i := 0 TO numElems-1 DO
|
|
|
+ SYSTEM.GET(src+tag.pointerOffsets[i] + i * tag.recSize + tag.pointerOffsets[j], sval);
|
|
|
+ CheckAssignment(dest+ i * tag.recSize + tag.pointerOffsets[j], sval);
|
|
|
+ END;
|
|
|
+ END;
|
|
|
SYSTEM.MOVE(src,dest,tag.recSize * numElems);
|
|
|
INC(assigns);
|
|
|
END AssignArray;
|
|
@@ -1593,7 +1754,12 @@ BEGIN
|
|
|
ASSERT(freeBlock.size MOD BlockSize = 0)
|
|
|
END;
|
|
|
|
|
|
- currentMarkValue := 1;
|
|
|
+ currentMarkValue := GenerationMask;
|
|
|
+ currentGeneration := Old;
|
|
|
+ FOR i := 0 TO currentGeneration DO
|
|
|
+ generationMarkValues[i] := currentMarkValue;
|
|
|
+ END;
|
|
|
+
|
|
|
(* extend the heap for one block such that module initialization can continue as long as Heaps.GC is not set validly *)
|
|
|
Machine.ExpandHeap(1, 1, memBlock, beginBlockAdr, endBlockAdr); (* try = 1, size = 1 -> the minimal heap block expansion is performed *)
|
|
|
IF endBlockAdr > beginBlockAdr THEN
|
|
@@ -1608,6 +1774,21 @@ BEGIN
|
|
|
|
|
|
END Init;
|
|
|
|
|
|
+PROCEDURE SetYoung*;
|
|
|
+BEGIN
|
|
|
+ Machine.Acquire(Machine.Heaps);
|
|
|
+ currentGeneration := Young;
|
|
|
+ Machine.Release(Machine.Heaps);
|
|
|
+END SetYoung;
|
|
|
+
|
|
|
+PROCEDURE SetOld*;
|
|
|
+BEGIN
|
|
|
+ Machine.Acquire(Machine.Heaps);
|
|
|
+ currentGeneration := Old;
|
|
|
+ Machine.Release(Machine.Heaps);
|
|
|
+END SetOld;
|
|
|
+
|
|
|
+
|
|
|
|
|
|
PROCEDURE SetHeuristic*;
|
|
|
BEGIN
|
|
@@ -1664,10 +1845,10 @@ TraceHeap:
|
|
|
Co
|
|
|
|
|
|
|
|
|
-Compiler.Compile -p=Win32G
|
|
|
+Compiler.Compile -p=Win32G --writeBarriers --traceModule=Trace
|
|
|
Runtime.Mod Trace.Mod Generic.Win32.Kernel32.Mod Win32.Machine.Mod Heaps.Mod
|
|
|
Generic.Modules.Mod Win32.Objects.Mod Win32.Kernel.Mod KernelLog.Mod Plugins.Mod Streams.Mod Pipes.Mod
|
|
|
-Commands.Mod I386.Reals.Mod Generic.Reflection.Mod TrapWriters.Mod CRC.Mod SystemVersion.Mod
|
|
|
+Commands.Mod I386.Reals.Mod Generic.Reflection.Mod
|
|
|
Win32.Traps.Mod Win32.WinTrace.Mod Win32.StdIO.Mod Locks.Mod Win32.Clock.Mod Disks.Mod Files.Mod
|
|
|
Dates.Mod Strings.Mod UTF8Strings.Mod FileTrapWriter.Mod Caches.Mod DiskVolumes.Mod
|
|
|
OldDiskVolumes.Mod RAMVolumes.Mod DiskFS.Mod OldDiskFS.Mod OberonFS.Mod FATVolumes.Mod FATFiles.Mod
|
|
@@ -1677,9 +1858,19 @@ StringPool.Mod ObjectFile.Mod GenericLinker.Mod GenericLoader.Mod BootConsole.Mo
|
|
|
|
|
|
~
|
|
|
|
|
|
-Compiler.Compile -p=Win32G --traceModule=Trace Heaps.Mod ~
|
|
|
+Compiler.Compile -p=Win32G --traceModule=Trace --writeBarriers Heaps.Mod ~
|
|
|
StaticLinker.Link --fileFormat=PE32 --fileName=A2.exe --extension=GofW --displacement=401000H Runtime Trace Kernel32 Machine Heaps Modules Objects Kernel KernelLog Streams Commands FIles WinFS Clock Dates Reals Strings Diagnostics BitSets StringPool ObjectFile GenericLinker Reflection GenericLoader BootConsole ~
|
|
|
-FSTools.CloseFiles A2M.exe ~
|
|
|
+FSTools.CloseFiles A2.exe ~
|
|
|
+
|
|
|
+
|
|
|
+FoxBinarySymbolFile.Test /temp/obj/Heaps ~
|
|
|
+
|
|
|
+Heaps.ShowCards
|
|
|
+
|
|
|
+(* enable generational garbage collection *)
|
|
|
+Heaps.SetYoung
|
|
|
+(* disable generational garbage collection *)
|
|
|
+Heaps.SetOld
|
|
|
|
|
|
+Kernel.GC
|
|
|
|
|
|
-FoxBinarySymbolFile.Test /temp/obj/Heaps ~
|