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 instead of 201. This error goes undetected. A user has to make sure that the initialization is done in a correct way.

Our Solution

Before compilation all top-level classes (also called root classes) can be specified. This list will be parsed from left to right and the imports will be resolved in this order. If there are problems with cyclic imports, the linker will output a warning. In the target image the classes should be ordered in the same manner. The kernel will call the class constructors accordingly. This would allow to call the constructors in the supervisor mode (configuration of hardware) and subsequently change to user mode.
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.
Java does not define the order of initialization clearly. If tests on the host and the target should lead to the same result, the following solution would be appropriate: the class constructor of a otherwise empty helper class calls all the other class constructors. This solution would also allow to get rid of the system table.

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.1428319757.txt.gz · Last modified: 2016/02/25 13:33 (external edit)