Super Prev Next

Run-time support

Some language features are implemented in the run-time library, including:

XDS provides an integrated Modula-2 and Oberon-2 run-time library, taking into account the possibility that modules written in both languages are used in one project. As a rule, if you do not use a particular feature, the part of RTS that implements that feature will not be added to your executable program. For example, if your program is written entirely in Modula-2, the Oberon-2 part of RTS (garbage collector, meta-language facilities) will not included.

The integrated memory manager is described in Memory management. The section The oberonRTS module describes an interface to the Oberon-2 run-time support.


Super Prev Next

Memory management

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:

If the memory block still cannot be allocated after the call to the garbage collector, the exception XEXCEPTIONS.noMemoryException will be raised by the Oberon-2 memory allocation procedure /In Modula-2 it has to return NIL if failed to allocate a memory block./ .

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.


Super Prev Next

Postmortem history

If the option GENHISTORY was set ON when your program was compiled, the run-time system dumps a procedure call stack into a file called errinfo.$$$, which may then be read by the HIS utility to print each item with

Note: all modules constituting your program should be compiled with the option LINENO set ON.

To print the history, RTS scans the stack of the coroutine that caused an exception and tries to find procedure calls. This is not a trivial task because of the highly optimized code generated by the compiler. For example, not all procedures have a stack frame.

For each pointer to the code segment on the stack RTS checks the previous command. If this command is a call command, it assumes that this is a procedure call. It is unlikely that RTS misses a procedure call, but it can be cheated by something that looks like a procedure call. As a rule, it is caused by uninitialized local variables, especially character arrays.

The first line of the history is always correct. For each line, except the first one, we recommend to check that the procedure shown in the previous line is called from the given line.

From the other hand, if you turn the GENFRAME option on, the code will be a bit slower, but RTS will scan stack frames of the procedures and the history will show absolutely correct addresses and line numbers. Procedure names are almost always valid except the case of lack of debug information in some modules - probably compiled by foreign compilers or by XDS with not all debug flags set. So you should not rely on procedure names hard.

Turning the GENHISTORY option ON does not slow down your code, as it only adds an extra call to the initialization routine. 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.


Super Prev Next

The oberonRTS module

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.


Super Prev Next

Types and variables

    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 *)


Super Prev Next

Garbage collection


Super Prev Next

Collect - Garbage Collector

    PROCEDURE Collect;

Invokes the garbage collector.


Super Prev Next

GetInfo - Get Memory Information

    PROCEDURE GetInfo(VAR objects, busymem: CARDINAL);

Returns the number of allocated objects and the total size of the allocated memory.


Super Prev Next

Object finalization

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.


Super Prev Next

Finalizer - Type of a finalization procedure

    TYPE Finalizer = PROCEDURE (SYSTEM.ADDRESS);


Super Prev Next

InstallFinalizer - Set a finalizer to an object

    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).

Super Prev Next

Example

    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;


Super Prev Next

Meta-language facilities

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.


Super Prev Next

Search - Search a Module by its Name

    PROCEDURE Search(name: ARRAY OF CHAR): Module;

Returns a module by its name or nullModule.


Super Prev Next

NameOfModule - Name of Module

    PROCEDURE NameOfModule(m: Module;
                    VAR name: ARRAY OF CHAR);

Returns the name of the Module.


Super Prev Next

ThisCommand - Get Command by its Name

    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.


Super Prev Next

ThisType - Get Type by its Name

    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.


Super Prev Next

SizeOf - Size of Type

    PROCEDURE SizeOf(t: Type): INTEGER;

Returns the size (in bytes) of an object of the type t.


Super Prev Next

BaseOf - Base of Type

    PROCEDURE BaseOf(t: Type; level: INTEGER): Type;

Returns the level-th base type of t.


Super Prev Next

LevelOf - Level of Type Extension

    PROCEDURE LevelOf(t: Type): INTEGER;

Returns a level of the type extension.


Super Prev Next

ModuleOf - Module of Type

    PROCEDURE ModuleOf(t: Type): Module;

Returns the module in which the type t was declared.


Super Prev Next

NameOfType - Name of Type

    PROCEDURE NameOfType(t: Type; VAR name: ARRAY OF CHAR);

Returns the name of the record type t.


Super Prev Next

TypeOf - Type of Object

    PROCEDURE TypeOf(obj: SYSTEM.ADDRESS): Type;

Returns the type of the object obj.


Super Prev Next

NewObj - Create Object

    PROCEDURE NewObj(type: Type): SYSTEM.ADDRESS;

Creates a new object of the type type.


Super Prev Next

Module iterators

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).


Super Prev Next

NameIterator - Iterator Type

    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.


Super Prev Next

IterModules - Iterate all Modules

    PROCEDURE IterModules(context: SYSTEM.ADDRESS;
                             iter: NameIterator);

The procedure iterates all Oberon-2 modules.


Super Prev Next

IterCommands - Iterate Commands

    PROCEDURE IterCommands(mod: Module;
                       context: SYSTEM.ADDRESS;
                          iter: NameIterator);

Iterates all commands implemented in the module mod.


Super Prev Next

IterTypes - Iterate Record Types

     PROCEDURE IterTypes(mod: Module;
                     context: SYSTEM.WORD;
                        iter: NameIterator);

Iterates all record types declared in the module mod.