home *** CD-ROM | disk | FTP | other *** search
- (*-------------------------------------------------------------------------*)
- (* *)
- (* Amiga Oberon Library Module: GarbageCollector Date: 02-Nov-92 *)
- (* *)
- (* © 1992 by Fridtjof Siebert *)
- (* *)
- (*-------------------------------------------------------------------------*)
-
-
- MODULE GarbageCollector;
-
- IMPORT Intuition,
- Exec*,
- OberonLib,
- SYSTEM*;
-
-
- CONST
-
- (*
- * many ist einfach eine große Integer-Konstante
- *)
-
- many * = MAX(LONGINT) DIV 8;
-
-
- TYPE
-
- (*
- * Big ist einfach ein großes Feld von Zeigern oder LONGINT-Werten
- *)
-
- Big * = ARRAY many OF SYSTEM.ADDRESS;
-
-
- (* --- Informationen über Typen: --- *)
-
-
- ObjectTypePtr * = UNTRACED POINTER TO ObjectType;
- ObjectType * = STRUCT
- id * : LONGINT; (* Zur Unterscheidung der verschiedenen arten von
- * allozierten Objekten
- *)
- END;
-
-
- (* --- Einfache Typen (RECORDs): --- *)
-
-
- CONST
- usualObject * = 1;
-
- TYPE
- UsualObjectTypePtr * = UNTRACED POINTER TO UsualObjectType;
- UsualObjectType * = STRUCT
- (bt * : ObjectType) (* INVARIANT: bt.id = usualObject *)
- size * : LONGINT; (* Größe des zu allozierenden Objects *)
- numRefs * : LONGINT; (* Anzahl der von diesem Object ausgehenden Referenzen *)
- refs * : Big; (* Offsets der von diesem Object ausgehenden Referenzen *)
- END;
-
-
- (* --- Offene Felder: --- *)
-
-
- CONST
- openArrayObject * = 2;
-
- TYPE
- OpenArrayObjectType * = STRUCT
-
- (*
- * Alle Objecte, die mit diesem Typ alloziert werden, müssen mit
- * AllocOpenArray() alloziert werden.
- *
- * Die Objekte selbst sind dann vom Typ OpenArrayObject und enthalten als
- * ersten Eintrag die Anzahl der Elemente des Feldes.
- *)
-
- (bt * : ObjectType) (* INVARIANT: bt.id = openArrayObject *)
- size * : LONGINT; (* Größe der einzelnen Elemente *)
- numRefs * : LONGINT; (* Anzahl der von jedem Feldelement ausgehenden
- * Referenzen
- *)
- refs * : Big; (* Offsets der von jedem Feldelement ausgehenden
- * Referenzen
- *)
- END;
-
-
- (* --- Interne Liste der ObjectTypes: --- *)
-
-
- MutatorPtr * = UNTRACED POINTER TO Mutator;
-
- InternalObjectTypePtr * = UNTRACED POINTER TO InternalObjectType;
- InternalObjectType * = STRUCT
- next : InternalObjectTypePtr; (* Link *)
- usecount : LONGINT; (* Referenzenzzählter auf diese Struktur
- * Da InternalObjectTypes nicht auf
- * ihresgleichen zeigen können, können
- * keine Zykel entstehen, so daß mit einem
- * Referenzzähler leicht ihre Lebensdauer
- * bestimmt werden kann.
- * Solange der Mutator exisitiert, ist
- * auf jeden Fall usecount >= 1.
- *)
- mutator : MutatorPtr; (* Mutator, dem dieser Typ gehört *)
- bt -: ObjectType; (* Die eigentliche ObjectType-Struktur, je
- * nach bt.id erweitert.
- *)
- END;
-
-
- (* --- Informationen über Variablen: --- *)
-
-
- (* Dieses Record muß innerhald des betroffenen Variablenbereichs liegen.
- * die in Vars.typ enthaltenen Offsets für Zeiger sind relativ zu
- * ADR(Vars)!
- *)
-
- VarsPtr * = UNTRACED POINTER TO Vars;
- Vars * = STRUCT
- next*: VarsPtr; (* internal link *)
- typ *: UsualObjectTypePtr;
- (* Typinformationen. Da ein Variablenbereich nicht
- * länger existieren darf als der dazugehörende
- * Mutator, zeigt typ direkt auf den ObjectType,
- * nicht auf ein extra alloziertes Typ-Objekt.
- *)
- END;
-
-
- (* --- Informationen über Mutatoren: --- *)
-
-
- Mutator * = STRUCT
- next ,
- prev : MutatorPtr; (* wird bei AddMutator() gesetzt *)
- globals *: VarsPtr; (* Liste der globalen Variablen *)
- locals *: VarsPtr; (* Liste der lokalen Variablen *)
- blockinfos : InternalObjectTypePtr;
- (* Liste der allozierten ObjectTypes
- *)
- replyPort : Exec.MsgPortPtr; (* Zur Kommuniktion mit dem Garbage-
- * Collector-Task
- *)
- msg : Exec.MessagePtr;
- END;
-
-
- (* --- Informationen über allozierte Objekte: --- *)
-
-
- ObjectPtr * = UNTRACED POINTER TO Object;
- Object * = STRUCT
-
- next -: ObjectPtr; (* über diesen Zeiger sind die Objekte
- * einer Liste miteinander verbunden.
- *)
-
- flags *: SET; (* Flags, können mit AllocFlag() alloziert
- * werden, um global Objekte zu markieren.
- *)
-
- shade *: SET; (* Schattierung dieses Objektes. "0 IN shade"
- * gibt an, ob das Objekt grau ist.
- * "shade * (-{0})" ist die pink-Schattierung des
- * Objektes (shade muß dabei vorzeichenlos
- * interpretiert werden).
- *)
-
- typ -: InternalObjectTypePtr;
- (* Typ dieses Objekts. Da ein Objekt länger leben
- * kann als der Mutator, der es alloziert hat,
- *)
-
- mem *: Big; (* hier beginnt der Speicher für den User.
- * Alloc() und AllocOpenArray() ergeben einen
- * Zeiger auf dieses Element.
- *)
-
- END;
-
-
- (* --- Informationen über allozierte Objekte: --- *)
-
-
- OpenArrayObjectPtr * = UNTRACED POINTER TO OpenArrayObject;
- OpenArrayObject * = STRUCT
-
- length - : LONGINT; (* Anzahl Elemente dieses Objekts.
- *)
-
- object * : Object; (* Das eigentliche Object, enthält auch den eigentlichen
- * Speicher.
- *
- * invariant
- * object.typ.bt.id = openArrayType
- *
- *)
-
- END;
-
-
- CONST
-
- shadeOffset * = - 6; (* Offset von Object.shade von Object.mem aus.
- * Beim Pink-schattieren muß
- *
- * ADDQ.W #pink,shadeOffset(Object)
- *
- * ausgeführt werden, wobei 'Object' ein Adreß-
- * register ist, das einen Zeiger auf ein Objekt
- * enthält.
- *)
- byteGrayOffset * = - 5; (* Offset des untersten Bytes von Objekt.flags.
- * Beim Grauschattiren muß
- *
- * BSET.B #gray,byteGrayOffset(Object)
- *
- * ausgeführt werden, wobei 'Object' ein Adreß-
- * register ist, das einen Zeiger auf ein Objekt
- * enthält.
- *)
-
-
- (* Objekt.shades *)
- gray * = 0; (* Bitnummer des Grau-Bits *)
- pink * = 2; (* Beim pink-Schattieren zu addierender Wert *)
-
- black = 15;
- (* Gesetzt bei allen Objekten, die schwarz markiert sind. Dabei muß
- * folgende Bedingung immer erfüllt sein:
- *
- * P: Kein schwarzes Element darf auf ein weißes Element zeigen.
- *
- * Um dies zu erreichen, müssen
- *
- * a) Alle Mutatoren vor einer Zuweisung "p := q" q grau markieren
- *
- * b) Es muß sichergestellt sein, das der Collector q nicht weiß
- * markiert, bevor eine Zuweisung "p := q" vollständig aus-
- * geführt ist (d.h. slange q pink schattiert ist)
- *
- * c) Während des Markierungsprozeßes werden alle Objekte, auf die ein
- * graues Objekt zeigt, mit grau markiert, bevor das Objekt selbst
- * schwarz markiert wird.
- *
- *)
-
-
-
-
-
- (*
- * Der Mutator (das Programm, das Speicher vom Garbage-Collector alloziert)
- * muß bei jeder Zuweisung
- *
- * p := q;
- *
- * bei der p und q verfolgte Referenzen sind, folgenden Code erzeugen:
- *
- * move.l q,Ax;
- * addq.w #pink,shade(Ax);
- * bset.b #gray,byteGrayOffset(Ax);
- * move.l Ax,p;
- * subq.w #pink,shade(Ax);
- *
- * oder, wenn q NIL sein kann:
- *
- * move.l q,Ax;
- * move.l Ax,Dy
- * beq.s nil;
- * addq.w #pink,shade(Ax);
- * bset.b #gray,byteGrayOffset(Ax);
- * nil: move.l Ax,p;
- * move.l Ax,Dy; (+)
- * beq.s nil2;
- * subq.w #pink,shade(Ax);
- * nil2:
- *
- * (Die Anweisung (+) kann weggelassen werden, wenn p kein Adreßregister ist)
- *
- * Dieser Code ist wichtig, da sonst hängende Referenzen entstehen können, da
- * der Garbage-Collector evtl. nicht erkennen kann, das hier eine neue
- * Referenz auf q entsteht.
- *
- * Folgendes muß erfüllt sein:
- *
- * R: a) Bevor in q Grau gesetzt wird, muß q pink schattiert werden. Ansonsten
- * wird die grau-Markierung sofort wieder ungültig.
- * b) zwischen der grau-Markierung und der Zuweisung an p darf die pink-
- * Schattierung nicht entfernt werden, da sonst die grau-Markierung
- * ungültig wird
- * c) nach der Zuweisung muß die pink-Schattierung wieder entfernt werden
- * d) Es dürfen keine zwei Objekte vom gleichen Mutator gleichzeitig pink
- * schattiert sein.
- * e) Das selbe Objekt darf nicht mehrmals vom gleichen Mutator pink
- * schattiert sein.
- *
- *)
-
-
- (* --- Globale Variablen: --- *)
-
- (*
- * Die Variablen dürfen nur innerhalb von Forbid() und Permit() verändert
- * werden.
- *)
-
- CONST
-
- MaxMutators * = 3FFFH;
- (*
- * Es darf maximal MaxMutators Mutatoren geben.
- *)
-
-
- TYPE
-
- (*
- * Unsere Library-Base-Struktur.
- *)
-
- GarbageCollectorBasePtr * = UNTRACED POINTER TO GarbageCollectorBase;
-
- GarbageCollectorBase * = STRUCT
-
- (libNode - : Exec.Library) (* gewöhnlicher Library-Knoten *)
-
- (*
- * Folgende Elemente dienen nur der Statistik und der Untersuchung
- * des Laufzeitverhaltens des Collectors und der Mutatoren:
- *)
-
- activeObjects - : LONGINT; (* derzeit lebendige Objekte *)
- deadObjects - : LONGINT; (* derzeit tote Objekte *)
- totalMem - : LONGINT; (* insgesamt allozierter Speicher *)
-
- cycleCount - : LONGINT; (* Nummer dieses GC-Zyklus *)
-
- END;
-
-
- VAR
-
- base - : GarbageCollectorBasePtr;
-
- mutator * : Mutator;
-
- mutatorValid - : BOOLEAN;
-
-
- (*-------------------------------------------------------------------------*)
- (* *)
- (* Macros: *)
- (* *)
- (*-------------------------------------------------------------------------*)
-
-
- (* --- AddGlobals: --- *)
-
-
- PROCEDURE AddGlobals*(VAR mutator{8}: Mutator; adr{9}: VarsPtr);
- (* Fügt einen globalen Bereich mit verfolgten Referenzen hinzu.
- * Alle Referenzen müssen mit NIL vorinitialisiert sein.
- * adr muß in den Bereich der Variablen auf eine Vars-Struktur zeigen.
- * adr.typ muß auf eine ObjectType-Struktur zeigen. Die Offsets in ObjectType
- * sind relativ zu adr.
- * adr.next Wird als Link zum nächsten Variablen-Feld verwendet und von
- * dieser Prozedur verändert.
- *)
-
- BEGIN
- adr.next := mutator.globals;
- mutator.globals := adr;
- END AddGlobals;
-
-
- (* --- RemGlobals: --- *)
-
-
- PROCEDURE RemGlobals*(VAR mutator{8}: Mutator);
- (* entfernt den zuletzt mit AddGlobalss() hinzugefügten Variablenbereich
- *)
-
- BEGIN
- mutator.globals := mutator.globals.next;
- END RemGlobals;
-
-
- (* --- AddLocals: --- *)
-
-
- PROCEDURE AddLocals*(VAR mutator{8}: Mutator; adr{9}: VarsPtr);
- (* Fügt einen lokalen Bereich mit verfolgten Referenzen hinzu.
- * Alle Referenzen müssen mit NIL vorinitialisiert sein.
- * adr muß in den Bereich der Variablen auf eine Vars-Struktur zeigen.
- * adr.typ muß auf eine ObjectType-Struktur zeigen. Die Offsets in ObjectType
- * sind relativ zu adr.
- * adr.next Wird als Link zum nächsten Variablen-Feld verwendet und von
- * dieser Prozedur verändert.
- *)
-
- BEGIN
- adr.next := mutator.locals;
- mutator.locals := adr;
- END AddLocals;
-
-
- (* --- RemLocals: --- *)
-
-
- PROCEDURE RemLocals*(VAR mutator{8}: Mutator);
- (* Entfernt den zuletzt mit AddLocals() hinzugefügten Variablenbbereich
- *)
-
- BEGIN
- mutator.locals := mutator.locals.next;
- END RemLocals;
-
-
- (* --- RemLocals: --- *)
-
-
- PROCEDURE RemAllLocals*(VAR mutator{8}: Mutator);
- (* Entfernt alle mit AddLocals() hinzugefügten Variablenbbereiche
- *)
-
- BEGIN
- mutator.locals := NIL;
- END RemAllLocals;
-
-
- (* --- Routinen der Library: --- *)
-
-
- PROCEDURE AddGlobalsLib * {base,- 30}(VAR mutator{8}: Mutator;
- adr{9}: VarsPtr);
- PROCEDURE RemGlobalsLib * {base,- 36}(VAR mutator{8}: Mutator);
- PROCEDURE AddLocalsLib * {base,- 42}(VAR mutator{8}: Mutator;
- adr{9}: VarsPtr);
- PROCEDURE RemLocalsLib * {base,- 48}(VAR mutator{8}: Mutator);
- PROCEDURE RemAllLocalsLib * {base,- 54}(VAR mutator{8}: Mutator);
-
-
- (* --- AddMutator / RemMutator: --- *)
-
-
- PROCEDURE AddMutator * {base,- 60}(VAR mutator{8}: Mutator): BOOLEAN;
- (* Mutator ist für die identifikation der Variablen eines Tasks nötig.
- * Bevor es verwendet werden kann, muß es mit AddMutator dem Garbage-Collector
- * übergeben werden.
- *)
-
- PROCEDURE RemMutator * {base,- 66}(VAR mutator{8}: Mutator);
- (* Entfernt Mutator aus der Mutator-Liste.
- * RemMutator darf nur aufgerufen, nachdem es mit AddMutator() zur Mutator-Liste hinzugefügt
- * wurde.
- * Nach RemMutator darf mutator nicht mehr als mutator-Parameter für die anderen Prozeduren,
- * mit der Ausnahme von AddMutator(), verwendet werden.
- *)
-
-
- (* --- AllocType: --- *)
-
-
- PROCEDURE AllocType * {base,- 72}(VAR mutator {8}: Mutator;
- typ{9}: ObjectTypePtr): InternalObjectTypePtr;
- (*
- * Es wird Speicher für eine InternalObjectType-Struktur alloziert. Diese
- * Wird beim Allozieren von Objekten mit Alloc() nötig.
- *
- * Da die allozierten Objekte länger leben können als die Programme, die sie
- * alloziert haben, dürfen die ObjectTypes nicht im Datenbereich der Programme
- * liegen, sondern müssen extra alloziert werden.
- *
- * Ihr Speicher wird automatisch freigegeben, sobald der angegebene Mutator mit
- * RemMutator(mutator) entfernt wurde und keine Objekt mehr von diesem Typ ist.
- *
- * Hat das System keinen freien Speicher mehr, wird das Ergebnis auf NIL
- * gesetzt. Bevor dies geschieht, wird der aktuelle Garbage-Collection-Zyklus
- * beendet, d.h. das ein Aufruf dieser Prozedur bei Speichermangel
- * (SEHR) lange dauern kann.
- *)
-
-
- (* --- Alloc: --- *)
-
-
- PROCEDURE Alloc * {base,- 78}( typ{8}: InternalObjectTypePtr;
- VAR adr{9}: SYSTEM.ADDRESS);
- (*
- * Alloziert ein Object des gewählten Typs
- *
- * adr MUSS dabei eine verfolgte Variable sein, da die Adresse sonst
- * sofort wieder ungültig wäre, da das Object bei der nächsten Garbage-.
- * Collection gleich wieder eingesammelt wird.
- *
- * Hat das System keinen freien Speicher mehr, wird adr auf NIL gesetzt.
- * Bevor dies geschieht, wird der aktuelle Garbage-Collection-Zyklus
- * beendet, d.h. das ein Aufruf dieser Prozedur bei Speichermangel
- * (SEHR) lange dauern kann.
- *)
-
-
- (* --- NewPreferences: --- *)
-
-
- PROCEDURE NewPreferences*{base,- 84};
- (*
- * Teilt der Library mit, daß es neue Preferences in ENV: gibt und daß diese
- * baldmöglichst geladen werden sollen.
- *
- * Die neuen Preferences werden immer dann geladen, wenn die Library das erste
- * mal geöffnet wird, dh. wenn ihr OpenCnt von 0 auf 1 springt.
- *
- *)
-
-
- (* --- AllocOpenArray: --- *)
-
-
- PROCEDURE AllocOpenArray*{base,- 90}( typ{8}: InternalObjectTypePtr;
- VAR adr{9}: SYSTEM.ADDRESS;
- length{2}: LONGINT);
- (*
- * Alloziert ein Object eine offenen Feldtyps mit size Elementen.
- *
- * adr MUSS dabei eine verfolgte Variable sein, da die Adresse sonst
- * sofort wieder ungültig wäre, da das Object bei der nächsten Garbage-.
- * Collection gleich wieder eingesammelt wird.
- *
- * Hat das System keinen freien Speicher mehr, wird adr auf NIL gesetzt.
- * Bevor dies geschieht, wird der aktuelle Garbage-Collection-Zyklus
- * beendet, d.h. das ein Aufruf dieser Prozedur bei Speichermangel
- * (SEHR) lange dauern kann.
- *)
-
-
- (* --- WaitForCollector: --- *)
-
-
- PROCEDURE WaitForCollector * {base,- 96}(id{8}: MutatorPtr);
- (*
- * Wartet bis der nächste Garbage-Collector-Zyklus beendet ist. Dabei wird
- * die Priorität des Collectors bis der Zyklus beendet ist auf die dieses
- * Tasks gesetzt.
- *
- * Wenn man sicher gehen möchte, daß man mindestens einen kompletten Zyklus
- * wartet, muß man diese Routine 2 mal nacheinander aufrufen.
- *)
-
-
- (* --- AllocFlag: --- *)
-
-
- PROCEDURE AllocFlag* {base,- 102} (): LONGINT;
- (*
- * Ein Flag wird alloziert. Dieses Flag kann zum Kennzeichnen von Objekten
- * verwendet werden. Das allozierte Flag ist bei jedem von dieser Library
- * alloziertem Objekt gelöscht.
- *
- * Eine Mögliche Anwendungen der Flags ist das Durchwandern des von Objekten
- * aufgebauten Grafen, um diesen z.B. zu speichern.
- *
- * Das Flag kann mit
- *
- * move.l object,A0
- * move.l flag,D0
- * bset.w flag,-8(A0)
- *
- * gesetzt und entsprechend auch gelöscht werden.
- *
- * Das Ergebnis ist bei Erfolg zwischen 0 und 15.
- * Sind keine Flags mehr frei, ist das Ergebnis -1.
- *
- * Da es insgesamt nur 16 Flags gibt und ein Flag nur global für alle Objekte
- * alloziert werden kann, sollten immer möglichst wenig Flags über eine
- * möglichst kurze Zeit alloziert werden. Es sollte kein Programm über seine
- * gesamte Laufzeit eines oder mehrere Flags allozieren, von solchen
- * Programmen könnten dann nur maximal 16 gleichzeitig gestartet werden, was
- * meist eine grobe Einschränkung ist.
- *
- * Diese Routine kann in zukünftigen Versionen des Compilers in manchen Fällen
- * lange dauern.
- *)
-
-
- (* --- FreeFlag: --- *)
-
-
- PROCEDURE FreeFlag * {base,- 108} (flag{2}: INTEGER);
- (*
- * Das mit AllocFlag() allozierte Flag wird wieder freigegeben.
- *
- * Das Flag muß vorher bei allen Objekten, bei denen es gesetzt wurde,
- * wieder gelöscht werden.
- *
- * Future Enhancements:
- * Wenn mir jemand eine Anwendung zeigt, bei der es eine große Erleichterung
- * wäre, wenn das Flag automatisch gelöscht würde, werde ich diese Routine
- * so verbessern, daß das Flag nicht gelöscht werden muß. Das Löschen würde
- * dann vom Collector übernommen.
- *)
-
-
- (* --- AssignRef: --- *)
-
-
- PROCEDURE AssignRef * {base,- 114}(ref{8}: SYSTEM.ADDRESS;
- to {9}: SYSTEM.ADDRESS);
-
- (*
- * Kopiert den verfolgten Zeiger ref nach to^ (Wie bei to^ := ref).
- *
- * Ist ref#NIL, wird ref^ pink und grau markiert, wie dies bei
- * Zeigerzuweisungen nötig ist.
- *
- * ensure
- * to^ = ref
- *)
-
-
- (* --- Assign: --- *)
-
-
- PROCEDURE Assign * {base,- 120}(from{8},to{9} : SYSTEM.ADDRESS;
- type{10} : ObjectTypePtr);
-
- (*
- * Kopiert from^ nach to^ (Wie bei from^ := to^).
- *
- * Der Typ von to ist type. Alle von to erreichbaren Objekte werden grau markiert.
- * from und typ müssen dabei keine mit Alloc() allozierten Objekte sein, sondern
- * können auch einfache globale oder lokale Variablen sein.
- *
- * ACHTUNG: Diese Routine darf nicht gleichzeitig von mehreren Prozessen mit dem
- * selben Zielobjekt aufgerufen werden.
- *
- * require
- * type.id = usualObject;
- * from # NIL;
- * to # NIL;
- * ensure
- * from^ = to^
- *
- *)
-
-
- (* --- AssignOpenArray: --- *)
-
-
- PROCEDURE AssignOpenArray * {base,- 126}(from{8},to{9} : SYSTEM.ADDRESS;
- elementType{10}: UsualObjectTypePtr;
- length{2} : LONGINT);
-
- (*
- * Kopiert offenes Feld mit length Elementen und dem Elementtyp elementType
- * von from^ nach to^ (Wie bei from^ := to^).
- *
- * Alle von to erreichbaren Objekte werden grau markiert. from und typ müssen
- * dabei keine mit Alloc() allozierten Objekte sein, sondern können auch
- * einfache globale oder lokale Variablen sein.
- *
- * ACHTUNG: Diese Routine darf nicht gleichzeitig von mehreren Prozessen mit dem
- * selben Zielobjekt aufgerufen werden.
- *
- * require
- * elementType.id = usualObject;
- * from # NIL;
- * to # NIL;
- * length > 0;
- * ensure
- * from^ = to^
- *
- *)
-
-
- (* --- AssignRefs: --- *)
-
-
- PROCEDURE AssignRefs * {base,- 132}(from{8},to{9} : SYSTEM.ADDRESS;
- type{10} : ObjectTypePtr);
-
- (*
- * Kopiert alle Referenzen von from^ nach to^.
- *
- * Der Typ von to ist type. Alle von to erreichbaren Objekte werden grau markiert.
- * from und typ müssen dabei keine mit Alloc() allozierten Objekte sein, sondern
- * können auch einfache globale oder lokale Variablen sein.
- *
- * Diese Routine wird bei Zuweisungen in Hochsprachen benötigt, bei denen Teile
- * des Zielobjekts unverändert bleiben müssen, da diese z.B. Informationen
- * über das Objekt selbst enthalten, die unverändert bleiben müssen.
- *
- * Nach dem Aufruf dieser Routine können alle nicht zugewiesenen Werte z.B. mit
- * Exec.CopyMem zugewiesen werden (da die Referenzen bereits kopiert wurden,
- * macht es nichts, wenn sie nochmal kopiert werden, es sei denn, dies geschieht
- * gleichzeitig von mehreren Prozessen aus).
- *
- * require
- * type.id = usualObject;
- * from # NIL;
- * to # NIL;
- * ensure
- * -- Alle Referenzen in from^ sind gleich mit denen in to^
- *
- *)
-
-
- (* --- CallAssign: --- *)
-
-
- PROCEDURE CallAssign * (from,to : SYSTEM.ADDRESS;
- type : ObjectTypePtr); (* $SaveAllRegs+ *)
- (*
- * Wie Assign, nur mit Stack-Parametern. Wird vom Oberon-Compiler benutzt.
- *)
-
- BEGIN
- Assign(from,to,type);
- END CallAssign;
-
-
- (* --- AssignOpenArray: --- *)
-
-
- PROCEDURE CallAssignOpenArray * (from,to : SYSTEM.ADDRESS;
- elementType: UsualObjectTypePtr;
- length : LONGINT); (* $SaveAllRegs+ *)
- (*
- * Wie AssignOpenArray, nur mit Stack-Parametern. Wird vom Oberon-Compiler
- * benutzt.
- *)
-
- BEGIN
- AssignOpenArray(from,to,elementType,length);
- END CallAssignOpenArray;
-
-
- (* --- AssignRecord: --- *)
-
-
- PROCEDURE AssignRecord * (from,to : SYSTEM.ADDRESS;
- type : UsualObjectTypePtr); (* $SaveAllRegs+ *)
- (*
- * Vom Oberon-Compiler verwendet, um Variablen eines erweiterbaren RECORD-Typs
- * einander zuzuweisen. Dabei werden alle Elemente bis auf den Zeiger auf
- * den Typedescriptor zugewiesen.
- *)
-
- BEGIN
- AssignRefs(from,to,type);
- Exec.CopyMemAPTR(SYSTEM.VAL(LONGINT,from)+4,
- SYSTEM.VAL(LONGINT,to )+4,type.size - 4);
- END AssignRecord;
-
-
- (* --- New: --- *)
-
-
- PROCEDURE New * (VAR adr: SYSTEM.ADDRESS;
- typ: InternalObjectTypePtr);
- (*
- * Ruft Alloc() auf. Kann Alloc() das Object nicht allozieren, wird
- * OberonLib.OutOfMemHandler() aufgerufen und noch einmal versucht,
- * das Object zu allozieren. Dies geschieht so lange, bis das Programm
- * abgebrochen wird oder das Allozieren erfolgreich war.
- *
- * ensure
- * adr#NIL
- *)
-
- BEGIN
- REPEAT
- Alloc(typ,adr);
- IF adr=NIL THEN
- OberonLib.OutOfMemHandler();
- END;
- UNTIL adr#NIL;
- END New;
-
-
- (* --- NewOpenArray: --- *)
-
-
- PROCEDURE NewOpenArray * (VAR adr: SYSTEM.ADDRESS;
- typ: InternalObjectTypePtr;
- size: LONGINT);
- (*
- * Ruft AllocOpenArray() auf. Kann AllocOpenArray() das Object nicht
- * allozieren, wird OberonLib.OutOfMemHandler() aufgerufen und noch einmal
- * versucht, das Object zu allozieren. Dies geschieht so lange, bis das
- * Programm abgebrochen wird oder das Allozieren erfolgreich war.
- *
- * ensure
- * adr#NIL
- *)
-
- BEGIN
- REPEAT
- AllocOpenArray(typ,adr,size);
- IF adr=NIL THEN
- OberonLib.OutOfMemHandler();
- END;
- UNTIL adr#NIL;
- END NewOpenArray;
-
-
- (* --- New: --- *)
-
-
- PROCEDURE Allocate * (VAR adr: SYSTEM.ADDRESS;
- typ: InternalObjectTypePtr);
- (*
- * Ruft Alloc() auf. Kann Alloc() das Object nicht allozieren, wird
- * NIL zurückgegeben.
- *)
-
- BEGIN
- Alloc(typ,adr);
- END Allocate;
-
-
- (* --- NewOpenArray: --- *)
-
-
- PROCEDURE AllocateOpenArray * (VAR adr: SYSTEM.ADDRESS;
- typ: InternalObjectTypePtr;
- size: LONGINT);
- (*
- * Ruft AllocOpenArray() auf. Kann AllocOpenArray() das Object nicht
- * allozieren, wird NIL zurückgegeben.
- *)
-
- BEGIN
- AllocOpenArray(typ,adr,size);
- END AllocateOpenArray;
-
-
- (* --- DuplicateOpenArray: --- *)
-
-
- PROCEDURE DuplicateOpenArray * (VAR from,to: ARRAY 100000H OF SYSTEM.ADDRESS;
- typ: InternalObjectTypePtr;
- elementTyp: UsualObjectTypePtr;
- dims: INTEGER);
- (* $SaveAllRegs+ *)
-
- (*
- * Alloziert eine Kopie des offenen Feldes an adr[0..dims] und kopiert diese
- * nach to[0..dims]. to[dims] muß dem GC als verfolgte Referenz mitgeteilt
- * werden.
- *
- * Diese Routine wird vom Oberon-Compiler für das Kopieren von Offenen-Feld-
- * Parametern verwendet, wenn die Felder verfolgte Referenzen enthalten.
- *
- * ensure
- * to[0..dims-1] = adr[0..dims-1]
- * to[dims] # adr[dims]
- * to[dims]^ = adr[dims]^
- *)
-
- VAR
- length: LONGINT;
- i: INTEGER;
-
- BEGIN
- length := 1;
- i:=dims;
- REPEAT
- DEC(i);
- length := length * SYSTEM.VAL(LONGINT,from[i]);
- to[i] := from[i];
- UNTIL i=0;
- NewOpenArray(to[dims],typ,length);
- AssignOpenArray(from[dims],to[dims],elementTyp,length);
- END DuplicateOpenArray;
-
-
- (* --- AddType: --- *)
-
-
- PROCEDURE AddType * (VAR to : SYSTEM.ADDRESS;
- typ: ObjectTypePtr);
- (*
- * Ruft AllocType() auf. Kann AllocType() keinen Typ allozieren, wird
- * OberonLib.OutOfMemHandler() aufgerufen und noch einmal versucht,
- * den Typ zu allozieren. Dies geschieht so lange, bis das Programm
- * abgebrochen wird oder das Allozieren erfolgreich war.
- *
- * ensure
- * ot#NIL
- *)
-
- VAR
- execBase[4]: UNTRACED POINTER TO STRUCT dummy: ARRAY 276 OF CHAR;
- thisTask : UNTRACED POINTER TO STRUCT dummy: ARRAY 46 OF CHAR;
- trapData : UNTRACED POINTER TO STRUCT
- mutator : MutatorPtr;
- END;
- END;
- END;
-
- BEGIN
- REPEAT
- to := AllocType(execBase.thisTask.trapData.mutator^,typ);
- IF to=NIL THEN
- OberonLib.OutOfMemHandler();
- END;
- UNTIL to#NIL;
- END AddType;
-
-
- (* --- Halt: --- *)
-
-
- VAR
- OldHaltProc: PROCEDURE;
-
- PROCEDURE Halt;
- (*
- * Entfernt die GC-Informationen über die lokalen Variablen und ruft die alte
- * HALT-Prozedur auf.
- *)
- BEGIN
- mutator.locals := NIL;
- OldHaltProc;
- END Halt;
-
-
- (* --- Init: --- *)
-
-
- BEGIN
-
- (* $IF GarbageCollector *)
-
- base := Exec.OpenLibrary("garbagecollector.library",2);
- IF base=NIL THEN
- SYSTEM.SETREG(0,Intuition.DisplayAlert(
- 0,"\x00\x64\x14missing garbagecollector.library V2\o\o",50));
- HALT(0);
- END;
-
- IF AddMutator(mutator) THEN
-
- mutatorValid := TRUE;
- OberonLib.execBase.thisTask.trapData.mutator := SYSTEM.ADR(mutator);
- OldHaltProc := OberonLib.execBase.thisTask.trapData.haltProc;
- OberonLib.execBase.thisTask.trapData.haltProc := Halt;
-
- ELSE
-
- HALT(20); (* Etwas ging schief, normalerweise nur bei zu wenig Speicher *)
-
- END;
-
- CLOSE
-
- IF mutatorValid THEN RemMutator(mutator) END;
-
- IF base#NIL THEN Exec.CloseLibrary(base) END;
-
- (* $END *)
-
- END GarbageCollector.
-
-
-
-
-
-
-