home *** CD-ROM | disk | FTP | other *** search
- ****************************************************************************
- *
- * $RCSfile: GC.asm $
- * Description: Runtime support for the Oberon-A compiler
- *
- * Created by: fjc (Frank Copeland)
- * $Revision: 1.3 $
- * $Author: fjc $
- * $Date: 1994/05/16 16:32:13 $
- *
- * Copyright © 1994, Frank Copeland.
- * This file is part of the Oberon-A Library.
- * See Oberon-A.doc for conditions of use and distribution.
- *
- * Log entries are at the end of the file.
- *
- ****************************************************************************
- *
- * This file contains the MC68000 source code for part of the runtime support
- * library of the Oberon-A compiler. It contains the code to implement the
- * Oberon-A garbage collector.
- *
- * Other parts of the runtime system may be found in the other files in this
- * directory. The object files resulting from assembling these files are
- * concatenated to create OberonSys.lib.
- *
- * This code is by definition *not* re-entrant and is not suitable for
- * creating shared-code libraries.
- *
- ****************************************************************************
-
- ;---------------------------------------------------------------------------
- ; Program unit hunk name
- ; !! DO NOT CHANGE UNLESS YOU KNOW WHAT YOU ARE DOING !!
-
- TTL OberonSys
-
- ;---------------------------------------------------------------------------
- ; Imports
-
- INCLUDE "OberonSys.i"
-
- ABSEXECBASE EQU 4
- FreeMem EQU -210
-
- ;---------------------------------------------------------------------------
- ; Macros
-
- CALLSYS MACRO
- JSR \1(A6)
- ENDM
-
- ;---------------------------------------------------------------------------
- ; Defines
-
- SysBit EQU 0
- ArrayBit EQU 1
- MarkBitB EQU 7
- MarkBitL EQU 31
- tag EQU -4
- size EQU -12
- elemSize EQU -16
- arrpos EQU -20
- PtrTabOffset EQU 36
-
- ;---------------------------------------------------------------------------
- ; PROCEDURE OberonSys_GC ()
- ;
- ; A call to this procedure is generated by the compiler when it translates a
- ; call to SYSTEM.GC. OberonSys_GC implements a mark-and-sweep garbage
- ; collector. See TechNotes.doc and Memory.doc for a discussion of the
- ; memory management system and the garbage collector.
- ;
- ; This procedure forms the outer loop of the mark phase and OberonSys_Mark
- ; is the inner loop. It walks the list of global variable descriptors
- ; generated by the compiler and applies the mark algorithm to each global
- ; pointer variable. After marking is completed OberonSys_Sweep is called to
- ; collect the unmarked memory. The global variable descriptors are accessed
- ; through the offsetPtr variable. They consist of a link field, a pointer
- ; to the base of the corresponding module's global variables, and an array
- ; of offsets. The offsetPtr variable is also used to access this array by
- ; repeatedly incrementing it by the size of an offset (4 bytes). The offset
- ; array is terminated by a negative value which is initialised so that
- ; adding it to offsetPtr restores it to point to the base of the descriptor.
- ;
- ; VAR
- ; offsetPtr {A6} :
- ; POINTER TO UNION
- ; offsetBlock : RECORD
- ; link : ADDRESS;
- ; varBase : ADDRESS;
- ; END;
- ; offset : LONGINT;
- ; END;
- ; varBase {A4} : ADDRESS;
- ; ptr {A0} : ADDRESS;
- ; offset {D7} : LONGINT;
- ;
- ;---------------------------------------------------------------------------
-
- SECTION OberonSys,CODE
-
- XDEF OberonSys_GC
-
- OberonSys_GC:
-
- MOVEM.L A4-A5,-(A7) ; (* preserve registers *)
- LEA OberonSys_VAR,A5 ; (* load OberonSys_VAR *)
- MOVEA.L OS_GCVars(A5),A6 ; offsetPtr := OberonSys.GCVars;
- G1:
- MOVE.L A6,D0 ; WHILE offsetPtr # NIL DO
- BEQ.S G4
- MOVEA.L 4(A6),A4 ; varBase := offsetPtr.varBase;
- ADDQ.L #8,A6 ; INC (offsetPtr, 8);
- G2: ; LOOP
- MOVE.L (A6)+,D7 ; offset := offsetPtr.offset;
- ; INC (offsetPtr, 4)
- BMI.S G3 ; IF offset >= 0 THEN
- MOVE.L 0(A4,D7.L),D0 ; ptr := mem [varBase + offset];
- BEQ.S G2 ; IF (ptr # NIL)
- MOVE.L D0,A0
- BSET.B #MarkBitB,tag(A0) ; & Unmarked(ptr)
- BNE.S G2
- BTST.B #SysBit,tag+3(A0) ; & ~SysBlk (ptr) THEN
- BNE.S G2
- ; Already done by BSET above SetMark (ptr);
- BSR OberonSys_Mark ; OberonSys_Mark (ptr)
- BRA G2 ; END;
- G3: ; ELSE
- ADDA.L D7,A6 ; offsetPtr := offsetPtr+offset;
- SUBQ.L #4,A6 ; (* compensate for increment *)
- ; EXIT
- ; END
- ; END; (* LOOP *)
- MOVEA.L (A6),A6 ; offsetPtr := offsetPtr.link
- BRA.S G1
- G4: ; END; (* WHILE *)
- BSR OberonSys_Sweep ; OberonSys_Sweep ()
- MOVEM.L (A7)+,A4-A5 ; (* restore registers *)
- RTS
-
- ;---------------------------------------------------------------------------
- ;
- ; PROCEDURE OberonSys_Mark (q {A0} : Pointer)
- ;
- ; OberonSys_Mark is a direct implementation of the algorithm described in
- ; the Oberon Technical Notes, part 5 (see TechNotes.doc). It forms the
- ; inner loop of the mark phase and assumes that the root pointer variable
- ; passed in A0 has already been marked. The algorithm has been modified
- ; slightly to reflect the different tag encodings and memory block formats
- ; used by Oberon-A.
- ;
- ; Address registers A1-A3 and all the data registers are free on entry.
- ;
- ; VAR
- ; n {A1}, t {A2}, tos {A3} : Pointer;
- ; offset {D0}, tag {A4,D3} : LONGINT;
- ; qmask {D1}, ntag {D2} : SET;
- ;
- ;---------------------------------------------------------------------------
-
- SECTION OberonSys,CODE
-
- OberonSys_Mark:
-
- MOVE.L A4,-(A7) ; (* Create an extra free register *)
- BTST.B #ArrayBit,tag+3(A0) ; IF 1 IN q.tag THEN
- BEQ.S M1
- CLR.L arrpos(A0) ; q.arrpos := 0;
- MOVE.L #$80000002,D1 ; qmask := {1, 31}
- BRA.S M2
- M1: ; ELSE
- MOVE.L #$80000000,D1 ; qmask := {31}
- M2: ; END;
- MOVE.L A0,A2 ; t := q;
- MOVE.L tag(A0),D3 ; tag := q.tag - {1, 31} + PtrTabOffset
- AND.L #$7FFFFFFD,D3
- ADD.L #PtrTabOffset,D3
- SUB.L A3,A3 ; tos := NIL;
- Loop: ; LOOP {H}
- MOVE.L D3,A4 ; offset := mem[tag];
- MOVE.L (A4),D0
- BPL.S L3 ; IF offset < 0 THEN
- MOVE.L D3,D4 ; q.tag := tag + offset + qmask;
- ADD.L D0,D4
- OR.L D1,D4
- MOVE.L D4,tag(A0)
- BTST.B #ArrayBit,D1 ; IF 1 IN qmask
- BEQ.S L1
- MOVE.L elemSize(A0),D4
- ADD.L arrpos(A0),D4
- CMP.L size(A0),D4 ; & (q.arrpos + q.elemSize # q.size) THEN
- BEQ.S L1
- MOVE.L elemSize(A0),D4 ; INC(q.arrpos,q.elemSize);
- ADD.L D4,arrpos(A0)
- ADD.L D0,D3 ; INC(tag, offset + PtrTabOffset - 4);
- ADD.L #PtrTabOffset-4,D3
- ADD.L elemSize(A0),A2 ; INC(t, q.elemSize)
- BRA L5
- L1:
- MOVE.L A3,D4 ; ELSIF tos = NIL THEN
- BEQ Exit ; EXIT
- ; ELSE
- MOVE.L tag(A3),D1 ; qmask := tos.tag;
- MOVE.L D1,D3 ; tag := qmask - {1, 31};
- AND.L #$7FFFFFFD,D3
- AND.L #$80000002,D1 ; qmask := qmask * {1, 31};
- MOVE.L A3,A2 ; t := tos;
- BTST.B #ArrayBit,D1 ; IF 1 IN qmask THEN
- BEQ.S L2
- ADD.L arrpos(A3),A2 ; INC (t, tos.arrpos)
- L2: ; END;
- MOVE.L D3,A4 ; offset := mem[tag];
- MOVE.L (A4),D0
- MOVE.L 0(A2,D0.L),A1 ; n := mem[t + offset];
- MOVE.L A0,0(A2,D0.L) ; mem[t + offset] := q;
- MOVE.L A3,A0 ; q := tos;
- MOVE.L A1,A3 ; tos := n
- BRA.S L5 ; END
- L3: ; ELSE
- MOVE.L 0(A2,D0.L),D4 ; n := mem[t + offset];
- BEQ.S L5 ; IF (n # NIL) THEN
- MOVE.L D4,A1
- MOVE.L tag(A1),D2 ; ntag := n.tag;
- BTST.L #MarkBitL,D2 ; IF ~(31 IN ntag) [Unmarked]
- BNE.S L5
- BTST.L #SysBit,D2 ; & ~(0 IN ntag) THEN [~SysBlk]
- BNE.S L5
- MOVE.L D3,tag(A0) ; q.tag := tag + qmask;
- OR.L D1,tag(A0)
- ; MOVE.L D2,D4 ; n.tag := ntag + {31};
- ; BSET.L #MarkBitL,D4
- ; MOVE.L D4,tag(A1)
- BSET.B #MarkBitB,tag(A1) ; n.tag := n.tag + {31};
- BTST.B #ArrayBit,D2 ; IF ~(1 IN ntag) THEN
- BNE.S L4
- MOVE.L A3,0(A2,D0.L) ; mem[t + offset] := tos;
- MOVE.L A0,A3 ; tos := q;
- MOVE.L A1,A0 ; q := n;
- MOVE.L A0,A2 ; t := q;
- MOVE.L D2,D3 ; tag := ntag + PtrTabOffset - 4;
- ADD.L #PtrTabOffset-4,D3
- MOVE.L #$80000000,D1 ; qmask := {31}
- BRA.S L5
- L4:
- BTST.B #SysBit,D2 ; ELSIF ~(0 IN ntag) THEN
- BNE.S L5
- MOVE.L A3,0(A2,D0.L) ; mem[t + offset] := tos;
- MOVE.L A0,A3 ; tos := q;
- MOVE.L A1,A0 ; q := n;
- CLR.L arrpos(A0) ; q.arrpos := 0;
- MOVE.L A0,A2 ; t := q;
- MOVE.L D2,D3 ; tag := ntag - {1} + PtrTabOffset - 4;
- BCLR.B #ArrayBit,D3
- ADD.L #PtrTabOffset-4,D3
- MOVE.L #$80000002,D1 ; qmask := {1, 31}
- ; END (* ELSIF *)
- ; END (* IF *)
- ; END (* IF *)
- L5: ; END; (* ELSE *)
- ADDQ.L #4,D3 ; INC(tag, 4)
- BRA Loop ; END (* LOOP *)
- Exit:
- MOVE.L (A7)+,A4 ; (* restore A4 *)
- RTS
-
- ;---------------------------------------------------------------------------
- ;
- ; PROCEDURE OberonSys_Sweep ()
- ;
- ; This procedure implements the sweep phase of the garbage collector. It
- ; walks the list of allocated blocks anchored in the OberonSys.memList
- ; variable, unmarking marked blocks and freeing unmarked blocks.
- ;
- ; VAR
- ; tag {A0}, block {A1}, prev {A2}, next {A3} : ADDRESS;
- ; size {D0} : LONGINT;
- ;
- ;---------------------------------------------------------------------------
-
- SECTION OberonSys,CODE
-
- OberonSys_Sweep:
-
- LEA OS_memList(A5),A2 ; prev := ADR (OberonSys.memList);
- MOVEA.L OS_memList(A5),A3 ; next := OberonSys.memList;
- S1:
- MOVE.L A3,D0 ; WHILE next # NIL DO
- BEQ.S S6
- BCLR.B #7,4(A3) ; IF Marked (next) THEN
- BEQ.S S2
- ; Already done by BCLR above Unmark (next);
- MOVEA.L A3,A2 ; prev := next;
- MOVEA.L (A3),A3 ; next := next.link
- BRA.S S1
- S2: ; ELSE
- MOVEA.L A3,A1 ; block := next;
- MOVEA.L (A3),A3 ; next := next.link;
- MOVE.L A3,(A2) ; prev.link := next;
- MOVE.L 4(A1),D1
- BTST #0,D1 ; IF 0 IN mem.tag THEN
- BEQ.S S3
- MOVE.L D1,D0 ; size := mem.tag + 7
- ADDQ.L #7,D0
- BRA.S S5
- S3:
- BTST #1,D1 ; ELSIF 1 IN mem.tag THEN
- BEQ.S S4
- SUBQ.L #8,A1 ; DEC (mem, 12);
- SUBQ.L #4,A1
- MOVE.L 8(A1),D0 ; size := mem.size + 20
- ADDI.L #20,D0
- BRA.S S5
- S4: ; ELSE
- MOVEA.L 4(A1),A0 ; size := mem.tag.size + 8
- MOVE.L (A0),D0
- ADDQ.L #8,D0
- S5: ; END;
- MOVE.L ABSEXECBASE,A6
- CALLSYS FreeMem ; FreeMem(mem,size)
- ; END; (* IF *)
- BRA.S S1 ; END; (* WHILE *)
- S6:
-
- RTS
-
- ;---------------------------------------------------------------------------
-
- END ; OberonSys
-
- ****************************************************************************
- *
- * $Log: GC.asm $
- * Revision 1.3 1994/05/16 16:32:13 fjc
- * - Fixed bug in OberonSys_Mark. It didn't check for SysBlks
- * in the right place and was trying to trace them as if they
- * RecordBlks. What a maroon.
- *
- * Revision 1.2 1994/05/12 20:31:15 fjc
- * - Prepared for release
- *
- * Revision 1.1 1994/01/15 18:31:52 fjc
- * Start of revision control
- *
- * (11 Jan 1994) First implementation
- * ( 4 Jan 1994) Stub created.
- *
- ****************************************************************************
-
-