Syntax10.Scn.Fnt ParcElems Alloc Syntax24b.Scn.Fnt Syntax10i.Scn.Fnt StampElems Alloc 24 Apr 96 Syntax10b.Scn.Fnt Syntax12b.Scn.Fnt (* AMIGA *) MODULE Kernel; (* jt/su 90-92, cn/shml 24 May 93, (* WARNING: do not use NEW nor SYSTEM.NEW in this module !! << added jt/mh/shml/bh's finalization, shml, 28 Jul 94 << added incremental heap block allocation, shml, 21 Sep 94 IMPORT SYSTEM,Amiga,Dos:=AmigaDos; CONST ModNameLength*=24; nofLists=9; Unit=16; MarkBit*=0; sysblk=1; freeblk=2; nextOff=4; (* next in free block *) hOff=Unit; (* NOTE: The implementation assumes hOff MOD Unit=0! *) hSizeOff=0; hNextOff=4; (*<< offset of first usable word, size of Amiga block, next Amiga block*) Nil=LONG(LONG(0)); MaxExts=7; ptrTabOffset=40+(MaxExts+1)*4; maxcand=1000; BlockSize=65536 (*2000000*); (*<<*) TYPE ModuleName*=ARRAY ModNameLength OF CHAR; Module*=POINTER TO ModuleDescriptor; ModuleDescriptor*=RECORD link*:Module; nofentries*, nofcoms*, nofptrs*, nofimps*:INTEGER; refcnt*:INTEGER; constSize*, dataSize*, codeSize*, refSize*:LONGINT; key*:LONGINT; name*:ModuleName; entries*, commands*, pointers*, imports*, const*, data*, code*, refs*:LONGINT END; Finalizer*=PROCEDURE(obj:SYSTEM.PTR); (*<<*) FinObject=POINTER TO FinObjectDesc; (*<<*) FinObjectDesc=RECORD (*<<*) next:FinObject; obj:LONGINT; finalize:Finalizer END; (*<=size THEN EXIT END ; (* why not IF t>=size ?? *) prev:=adr; SYSTEM.GET(adr+nextOff,adr); END ; (* A block large enough is located. If the unneeded size is larger than the blocks managed in the freelist, it is simply shortened. Otherwise it is completely unliked, and the initial remaining block linked into the appropriate small block free list. *) restsize:=t - size - ASH(1,freeblk); SYSTEM.PUT(adr+restsize,size+ASH(1,freeblk)); IF restsize >= nofLists*Unit THEN (*resize*) (* Shouldn't it be restsize >= nofLists*Unit ??? *) SYSTEM.PUT(adr,restsize+ASH(1,freeblk)) ELSE (*unlink*) SYSTEM.GET(adr+nextOff,next); IF prev=Nil THEN bigBlocks:=next ELSE SYSTEM.PUT(prev+nextOff,next) END ; IF restsize > 0 THEN (*move*) di:=restsize DIV Unit; SYSTEM.PUT(adr,restsize+ASH(1,freeblk)); SYSTEM.PUT(adr+nextOff,freeList[di]); freeList[di]:=adr END END ; INC(adr,restsize) END ; Erase the allocated block, and put the type tag at the beginning of the block. i:=4; WHILE i= size THEN EXIT END ; (* why not IF t>=size ?? *) prev:=adr; SYSTEM.GET(adr+nextOff,adr) END ; (* A block large enough is located. If the unneeded size is larger than the blocks managed in the freelist, it is simply shortened. Otherwise it is completely unliked, and the initial remaining block linked into the appropriate small block free list. *) restsize:=t - size - ASH(1,freeblk); SYSTEM.PUT(adr+restsize,size+ASH(1,freeblk)); IF restsize >=nofLists*Unit THEN (*resize*) (* Shouldn't it be restsize >= nofLists*Unit ??? *) SYSTEM.PUT(adr,restsize+ASH(1,freeblk)) ELSE (*unlink*) SYSTEM.GET(adr+nextOff,next); IF prev=Nil THEN bigBlocks:=next ELSE SYSTEM.PUT(prev+nextOff,next) END ; IF restsize > 0 THEN (*move*) di:=restsize DIV Unit; SYSTEM.PUT(adr,restsize+ASH(1,freeblk)); SYSTEM.PUT(adr+nextOff,freeList[di]); freeList[di]:=adr END END ; INC(adr,restsize) END ; The type tag points to the end of the block, where just the size is stored (a pseudo type tag?). To distinguish this block from a regular one, the sysblock flag is set. Note: These blocks are not zeroed. i:=adr+size - 8; SYSTEM.PUT(i,size); SYSTEM.PUT(adr,i+ASH(1,sysblk)); RETURN adr+4 END SysNew; PROCEDURE RegisterObject*(obj:SYSTEM.PTR; finalize:Finalizer); (*<<*) f:FinObject; PROCEDURE new (VAR finObj:SYSTEM.PTR); (* finObj is initialized with tag, hack! *) BEGIN finObj:=SYSTEM.VAL(SYSTEM.PTR,New(SYSTEM.VAL(ADDRESS,finObj))) END new; BEGIN IF obj#NIL THEN new(f); f.obj:=SYSTEM.VAL(LONGINT,obj); f.finalize:=finalize; f.next:=fin; fin:=f; END; END RegisterObject; PROCEDURE^ Mark(q:ADDRESS); PROCEDURE CheckFin; (*<<*) f, prev, next:FinObject; tag:SET; BEGIN For each object in the finalization list, check if it is marked. If not, mark it to prevent Sweep() from freeing it, and move the finalization object to the list of finalizations which have to be performed. f:=fin; prev:=NIL; WHILE f#NIL DO next:=f.next; SYSTEM.GET(f.obj-4, tag); IF ~(MarkBit IN tag) THEN (* garbage object, put it into to-be-finalized list *) Mark(SYSTEM.VAL(ADDRESS, f.obj)); (* mark f.obj and all objects accessible from it *) IF prev=NIL THEN fin:=next ELSE prev.next:=next END; f.next:=toBeFin; toBeFin:=f; ELSE prev:=f; END; f:=next END; END CheckFin; PROCEDURE Finalize; (*<<*) f:FinObject; BEGIN WHILE toBeFin#NIL DO f:=toBeFin; toBeFin:=toBeFin.next; f.finalize(SYSTEM.VAL(SYSTEM.PTR, f.obj)) END; END Finalize; PROCEDURE FinalizeAll; (*<<*) f:FinObject; BEGIN f:=fin; WHILE f#NIL DO f.finalize(SYSTEM.VAL(SYSTEM.PTR, f.obj)); f:=f.next; END; END FinalizeAll; PROCEDURE Mark(q:ADDRESS); VAR p,tag,fld,n:ADDRESS; offset:LONGINT; tagbits:SET; BEGIN IF q#Nil THEN (* If pointer not NIL then get tagbits. *) SYSTEM.GET(q - 4,tagbits); IF ~(MarkBit IN tagbits) THEN (* If not yet marked, then mark now. *) SYSTEM.PUT(q - 4,tagbits+{MarkBit}); IF ~(sysblk IN tagbits) THEN (* If not a block allocate with SysNew() then ... *) p:=Nil; tag:=SYSTEM.VAL(LONGINT,tagbits)+ptrTabOffset; LOOP SYSTEM.GET(tag,offset); IF offset<0 THEN SYSTEM.PUT(q - 4,tag+offset+ASH(1,MarkBit)); IF p=Nil THEN EXIT END ; n:=q; q:=p; SYSTEM.GET(q - 4,tag); DEC(tag,ASH(1,MarkBit)); SYSTEM.GET(tag,offset); fld:=q+offset; SYSTEM.GET(fld,p); SYSTEM.PUT(fld,n) ELSE fld:=q+offset; SYSTEM.GET(fld,n); IF n#Nil THEN SYSTEM.GET(n - 4,tagbits); IF ~(MarkBit IN tagbits) THEN SYSTEM.PUT(n - 4,tagbits+{MarkBit}); IF ~(sysblk IN tagbits) THEN SYSTEM.PUT(q - 4,tag+ASH(1,MarkBit)); SYSTEM.PUT(fld,p); p:=q; q:=n; tag:=SYSTEM.VAL(LONGINT,tagbits)+(ptrTabOffset - 4); END END END END ; INC(tag,4); END END END END; END Mark; PROCEDURE Sweep; VAR heapBlock, prev, this, adr, end, start:ADDRESS; tag:SET; i, size, freesize, tagv:LONGINT; thisBlock:HeapBlock; BEGIN Clear the free lists and reset the size of allocations. i:=1; WHILE i 0 THEN start:=adr - freesize; SYSTEM.PUT(start,freesize+ASH(1,freeblk)); IF freesize 0 THEN (*collect last block*) start:=adr - freesize; SYSTEM.PUT(start,freesize+ASH(1, freeblk)); IF freesize r) OR (a[j] <= x) THEN EXIT END; a[i]:=a[j] END; a[i]:=x END Sift; PROCEDURE HeapSort (n:LONGINT; VAR a:ARRAY OF LONGINT); VAR l,r,x:LONGINT; BEGIN l:=n DIV 2; r:=n - 1; WHILE l > 0 DO DEC(l); Sift(l,r,a) END; WHILE r > 0 DO x:=a[0]; a[0]:=a[r]; a[r]:=x; DEC(r); Sift(l,r,a) END; END HeapSort; PROCEDURE MarkCandidates(n:LONGINT; VAR cand:ARRAY OF LONGINT); VAR adr,heapBlock,heapBlockEnd,next,lim:ADDRESS; i,ptr,tagv:LONGINT; tag:SET; BEGIN adr:=heap; i:=0; lim:=cand[n-1]; IF ODD(lim) THEN DEC(lim); END; heapBlock:=heap-hOff; (*<<*) SYSTEM.GET(heapBlock+hSizeOff, heapBlockEnd); INC(heapBlockEnd, heapBlock); (*<<*) WHILE adr <= lim DO SYSTEM.GET(adr,tag); tagv:=SYSTEM.VAL(LONGINT,tag - {freeblk, sysblk, MarkBit}); IF MarkBit IN tag THEN SYSTEM.GET(tagv, tagv); INC(adr, tagv) (* if marked block, skip *) ELSIF freeblk IN tag THEN INC(adr,tagv) (* if free block, skip *) ELSE (* not marked, check if stack pointer bound! *) SYSTEM.GET(tagv,tagv); ptr:=adr+4; WHILE (cand[i] mark it! *) IF sysblk IN tag THEN SYSTEM.PUT(adr,tag+{MarkBit}) ELSE Mark(ptr) END END ; adr:=next END; IF adr >= heapBlockEnd THEN (*<<*) SYSTEM.GET(heapBlock+hNextOff, heapBlock); (* heapBlock:=heapBlock.next *) IF heapBlock#Nil THEN adr:=heapBlock+hOff; SYSTEM.GET(heapBlock+hSizeOff, heapBlockEnd); INC(heapBlockEnd, heapBlock); ELSE RETURN (* end of Amiga blocks! *) END END END; END MarkCandidates; PROCEDURE GC*(markStack:BOOLEAN); VAR frame:RECORD END ; m:Module; i,ptrOffset,nofcand:LONGINT; sp,p,heapstart,heapend,stackbottom,ptr:ADDRESS; cand:ARRAY maxcand OF LONGINT; BEGIN IF GCenabled THEN (* Go through all modules and call Mark for each pointer in each module. *) m:=modules; WHILE m#NIL DO (*Amiga.BreakPoint(m.name);*) i:=0; WHILE i0 THEN HeapSort(nofcand,cand); MarkCandidates(nofcand,cand) END END ; CheckFin; (*<< put all garbage objects into the to-be-finalized list *) (*<< i:=0; WHILE (i12 THEN INC(year); DEC(mon,12) END; t:=sec+ASH(min,6)+ASH(hour,12); d:=day+ASH(mon,5)+ASH(year MOD 100,9) END GetClock; PROCEDURE SetClock*(t,d:LONGINT); BEGIN (* Clock setting from Oberon is not allowed. *) END SetClock; BEGIN Init END Kernel.