deep

a Cross Development Platform for Java

User Tools

Site Tools


dev:crosscompiler:class_initialization

This is an old revision of the document!


Initialization

Initialize Classes

The Java compiler packes all initialization of static variables into a method called clinit. This is the class constructor. As an example the following source file with blocks 1 to 4 will be converted into Bytecode and is put linearly into clinit.

  static int[] a = new int[4];  // block 1
  static {  // block 2
    for (int i = 0; i < 3; i++) a[i] = i;
  }
  ...
  static int[] b = new int[4];  // block 3
  static {  // block 4
    for (int i = 0; i < 3; i++) b[i] = i;
  }

When will a class be initialized?

On the host we have a situation like this. The class constructor of a top-level class will be called first. Then follows the method main. The class constructor of an imported class will be called when:

  • accessing a static field of an imported class
  • calling a static method of an imported class
  • creating a new object defined by an imported class

A class will not be initialized just by declaring an object of this class. The calls of this class constructor is not included in the Bytecode but has to be made by the runtime system (by the JVM on the host).

Cyclic Imports

The code below shows what can happen.

  class A {
    static int a1 = b1 + 1;
    static int a2 = 200;
  }
  class B {
    static int b1 = 100;
    static int b2 = a2 + 1;
  }

Class A starts initializing, a1 = b1 + 1 causes clinit of class B to be executed after which clinit of class A finishes. a1 will be assigned the correct value of 101, but b2 will be assigned 1 instaed of 201. This error goes undetected. A user has to make sure that the initialization is done in a correct way.

Our Solution

Beim Linken sollen alle Top-Level Klassen als Parameter angegeben werden können. Diese Liste wird von links nach rechts geparst und die Imports in der richtigen Reihenfolge aufgelöst. Wenn sich Probleme mit zyklischen Imports ergeben, soll der Linker eine Warnung ausgeben. Im ausführbaren Image sollen die Klassen der Importreihenfolge nach geordnet sein, sodass das Laufzeitsystem die Konstruktoren nacheinander aufrufen kann. Das bietet auch die Möglichkeit, beispielsweise diese Konstruktoren im Supervisor-Modus auszuführen (Konfiguration von Hardware) und anschliessend in den User-Modus zu wechseln. It's important that the heap class and the kernel class are initialized first. For this they are put at the beginning of the list.
In Java ist die Initialisierungsreihenfolge nicht klar definiert. Falls Test auf dem Host und dem Target stets das gleiche Resultat ergeben sollen, bietet sich folgende Lösung an: Im Klassenkonstruktor einer obersten Hauptklasse (die ansonsten vollständig leer ist) werden alle anderen Klassenkonstruktoren aufgerufen. Bei dieser Lösung entfällt auch die Notwendigkeit einer Systemtabelle.

Initialisierung von Objekten

Die Initialisierung von Objekten wird in den Objektkonstruktoren zusammengefasst.

  int len = 4;  // block 1
  int[] a = new int[len];  
 
  public Test () {  // block 2
    for (int i = 0; i < len; i++) a[i] = i;
  }

Die Objektkonstruktoren heissen alle init im Bytecode und unterscheiden sich in der Parameterliste. Block 1 und 2 werden in init zusammengefasst. Beim Erzeugen eines Objektes wird stets zuerst mit Hilfe von new ein Block auf dem Heap alloziert. Anschliessend wird der Konstruktor der Oberklasse aufgerufen (dieser ruft seinerseits den Konstruktor der Oberklasse auf). Diese Aufrufe sind im Bytecode enthalten. Klassen dürfen auch Instanzinitialisierer enthalten, z.B.

  int[] data = new int[10];  
  {for (int i = 0; i < 10; i++) data[i] = i;}

Auch diese Instanzinitialisierer befinden sich im Bytecode in den Objektkonstruktoren.

dev/crosscompiler/class_initialization.1415017861.txt.gz · Last modified: 2016/02/25 13:33 (external edit)