deep

a Cross Development Platform for Java

User Tools

Site Tools


dev:crosscompiler:class_initialization

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 as follows. 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.

Initialization of Objects

The initialization of objects is done in the object constructors.

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

In the Bytecode these constructors carry the name init and vary in the parameter list. Block 1 and block 2 in the above code block will be combined in init. When creating an object a call to new allocates a block on the heap. Next, the constructor of the super class is called (which itself calls its super class constructor). These calls can be found in the Bytecode. Classes might also have instance initializers, such as:

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

These initializers go into the object constructors as well.

dev/crosscompiler/class_initialization.txt · Last modified: 2021/05/10 19:52 by ursgraf