Some language features are implemented in the run-time library, including:
The integrated memory manager is described in Memory management. The section The oberonRTS module describes an interface to the Oberon-2 run-time support.
The XDS integrated memory manager implements
The compiler provides the option GCAUTO and the equation HEAPLIMIT to control the memory management. They should be set when the top-level module of the program is compiled We recommend to set them in the configuration file or a project file.. The compiler uses their values when generating the RTS initialization call.
The equation HEAPLIMIT specifies the maximum size of the heap in bytes. If that equation is set to zero, the run-time system automatically determines heap size at startup and dynamically adjusts it according to application's memory use and system load.
The option GCAUTO allows the garbage collector to be called implicitly. If the option is not set the garbage collector must be called explicitly (See The oberonRTS module). The garbage collector is called implicitly by the memory allocation procedure in the following cases:
Note: In a pure Modula-2 program, the garbage collector is never invoked, so you may set the HEAPLIMIT equation to a very large value.
If the option GENHISTORY was set ON when your program was compiled, the run-time system prints a stack of procedure calls on abnormal termination of your program, including
Note: Turning the GENHISTORY option ON slows down your code, cause the translator inserts extra RTS calls into every generated function. It should be done when you compile the main module of your program, in its header, compiler command line, or project (we recommend the last approach).
The following example shows a sketch of a program and the procedure stack:
PROCEDURE P1; (* uninitialized variable: *) VAR x: ARRAY [0..50] OF INTEGER; BEGIN i:=i DIV j; (* line 50 *) END P1; PROCEDURE P2; BEGIN i:=i DIV j; (* line 100 *) END P2; PROCEDURE P3; BEGIN P1; (* line 150 *) END P3;
#RTS: No exception handler #6: zero or negative divisor ------------------------------------------------------------ Source file LINE OFFSET PROCEDURE ------------------------------------------------------------ "test.mod" 50 000000DE "test.mod" 100 0000024C "test.mod" 150 0000051D
It is obvious from the source text that the procedure P1 cannot be called from P2. The second line is superfluous.
The run-time support (RTS) is an integral part of the Oberon-2 language implementation. It includes command activation, memory allocation, garbage collection and meta-language facilities. The module oberonRTS (written in Modula-2) provides an interface to these features.
TYPE Module; (* run-time data structure for a module *) Type; (* run-time data structure for a data type *) Command = PROC; (* parameterless procedure *) CARDINAL = SYSTEM.CARD32;
VAR nullModule: Module; (* Null value of type Module *) nullType: Type; (* Null value of type Type *)
PROCEDURE Collect;
Invokes the garbage collector.
PROCEDURE GetInfo(VAR objects, busymem: CARDINAL);
Returns the number of allocated objects and the total size of the allocated memory.
A system with garbage collection has some specific features. Its main difference from systems without garbage collection is that deallocation of any system resource must be postponed until garbage collection. For example, let some data structure contain descriptors of open files. To close a file (i.e. to destroy its descriptor), one needs to know that there are no references to that file. This information becomes known only in the course of garbage collection. The same argument also holds for other kinds of resources.
One immediate implication is that there must be some finalization mechanism: the ability to perform certain operations with an object when there are no more references to it.
XDS allows a finalization procedure to be attached to any dynamically allocated object.
TYPE Finalizer = PROCEDURE (SYSTEM.ADDRESS);
PROCEDURE InstallFinalizer(f: Finalizer;
obj: SYSTEM.ADDRESS);
The procedure sets the finalization procedure f for the object obj. That procedure will be called when the object becomes unreachable.
Note: a finalizer is called on the GC stack (stack size is limited).
TYPE Obj = POINTER TO ObjDesc; ObjDesc = RECORD file: File; (* file handler *) END; PROCEDURE Final(x: SYSTEM.ADDRESS); VAR o: Obj; BEGIN o:=SYSTEM.CAST(Obj,x); IF o.file # NIL THEN Close(file) END; END Final; PROCEDURE Create(): Obj; VAR o: Obj; BEGIN NEW(o); o.file:=NIL; oberonRTS.InstallFinalizer(Final,o); TryOpen(o.file); END Create;
The meta-programming operations can be used to retrieve the type of an object, to create an object of the given type, to get the name of a type and a type by its name, etc.
PROCEDURE Search(name: ARRAY OF CHAR): Module;
Returns a module by its name or nullModule.
PROCEDURE NameOfModule(m: Module;
VAR name: ARRAY OF CHAR);
Returns the name of the Module.
PROCEDURE ThisCommand(m: Module; name: ARRAY OF CHAR; ): Command;
Returns the command (parameterless procedure) named "name" in the module m or NIL, if the command does not exist.
PROCEDURE ThisType(m: Module; name: ARRAY OF CHAR): Type;
Returns the type named "name" declared in the module m or nullType, if there is no such type.
PROCEDURE SizeOf(t: Type): INTEGER;
Returns the size (in bytes) of an object of the type t.
PROCEDURE BaseOf(t: Type; level: INTEGER): Type;
Returns the level-th base type of t.
PROCEDURE LevelOf(t: Type): INTEGER;
Returns a level of the type extension.
PROCEDURE ModuleOf(t: Type): Module;
Returns the module in which the type t was declared.
PROCEDURE NameOfType(t: Type; VAR name: ARRAY OF CHAR);
Returns the name of the record type t.
PROCEDURE TypeOf(obj: SYSTEM.ADDRESS): Type;
Returns the type of the object obj.
PROCEDURE NewObj(type: Type): SYSTEM.ADDRESS;
Creates a new object of the type type.
The module oberonRTS provides procedures which can be used to iterate all loaded modules, all commands, and all object types (i.e., exported record types).
TYPE NameIterator = PROCEDURE ( (*context:*) SYSTEM.ADDRESS, (*name:*) ARRAY OF CHAR ): BOOLEAN;
A procedure of type NameIterator is called by an iterator on each iterated item. An iterator passes the name of the item along with the so-called context word. This allows some context information to be passed to the user-defined procedure (e.g., a file handler). If the procedure returns FALSE, the iteration is terminated.
PROCEDURE IterModules(context: SYSTEM.ADDRESS; iter: NameIterator);
The procedure iterates all Oberon-2 modules.
PROCEDURE IterCommands(mod: Module; context: SYSTEM.ADDRESS; iter: NameIterator);
Iterates all commands implemented in the module mod.
PROCEDURE IterTypes(mod: Module; context: SYSTEM.WORD; iter: NameIterator);
Iterates all record types declared in the module mod.