deep

a Cross Development Platform for Java

User Tools

Site Tools


dev:crosscompiler:cfr

Class File Reader

Course of Action

Build

System classes as indicated by the configuration are loaded first. After this the root classes are loaded. For each class all other classes which are referenced in the constant pool and which have a class file (arrays may be referenced but have no class files) are kept in an import list and subsequently loaded.
System classes are classes like the kernel or heap. They must be loaded in any case.

Constant Pool

In the first run all entries are read. During the second run objects of type item are created if necessary and references are resolved. For every class, method or field an object is inserted in the object directory. In the third run the constant pool is reduced and includes now only references to the object directory.

Architecture of deep class file reader

Each item has the fields index, offset and address. The meaning of this fields varies with the type of the item and is described in Fields of Item.

Special consideration has to be paided for references to arrays. If an array is created as in

  ClassA[] obj = new ClassA[];

there will be a reference to [LClassA; in the constant pool and the class file reader creates an array descriptor object. However, there is no such reference for the following code

  Object obj = new ClassA[];

and in the Bytecode we only have anewarray ClassA. For this case we must make sure that an array descriptor is created as well. The same is true for arrays of base types.
For each class an array interfaces holds all interfaces which this class implements. In if this interfaces extend other interfaces, the superinterfaces are included in this array as well.

Bytecode Analysis

The Bytecode of all methods are analyzed and the attribute flags of all classes and methods are properly set. For this purpose each object of the object directory has a field accAndPropFlags. In the interface org.deepjava.classItems.ICclassFileConsts many flags are defined, such as

  byte apfPublic = 0,	
        apfPrivate = 1, 	
        apfProtected = 2, 		
        apfStatic = 3, 			
        ...
  byte dpfBase = 15; 
        dpfClassLoaded = dpfBase+0,	
        dpfRootClass = dpfBase+1,
        ...

For instance, each class will be marked if an instance of it is ever created or a class will be marked if one of its methods is ever called with invokeinterface.

Stubs

When reading the constant pool of a class many fields or methods of other classes are needed for whom entries in the object directory were not yet created. For these stubs are created. At the end all stubs have to be replaced by their real object.

Finish

At the end all stubs have to be replaced, miscellaneous class information is added, fields and methods are sorted.

Classes, Interfaces and Arrays

Generally all items are linked in lists (using the field next). All root classes are listed in a array rootClasses which is a static member of the class org.deepjava.classItems.Class. There are more lists (all static members in the same class), like:

  • initClasses: Regular classes and interfaces which have an initializer (a class constructor, see Initialization). This classes are linked with the field nextClass.
  • nonInitClasses: Regular classes without initialization. Linked with the field nextClass.
  • arrayClasses: Arrays, linked with the field nextArray. For type tests for higher dimensional arrays, the lower dimensional arrays must be present as well. As references to those serve the fields nextHigherDim and nextLowerDim.
  • typeChkInterfaces: See the comment below.

There a a special case where an interface needs a type descriptor. This happens when type testing for an array of interfaces, see Type Checking.

  Object o = new InterfaceA[10]; 
  if (o instanceof InterfaceA[]) ...

Such interfaces are listed and linked with the field nextTypeChkInterface. This field is not shown in the following overview.

All classes, interfaces and arrays are linked in several lists

Arrays have java/lang/Object as superclass, therefore their type descriptor must allow for calling its inherited methods. Further there are two arrays containing lists with regular classes and interfaces, respectively. Each list contains classes with the same extension level. The field nextExtLevClass is used for linking. In the figure above the links are not all shown for simplicity.

Fields

When parsing the constant pool all fields are denoted with the tag Fieldref. Each Fieldref entry has two further indices into the constant pool. These denote the class and an entry NameAndType, which again has to further indices with the name and the type. For each field a new object is added to the object directory.

The class file reader adds all fields of a class in three linked lists:

  • Instance fields → Class.instFields
  • Class fields → Class.classFields
  • Constant fields → Class.constFields (don't go into the target image!)

The three lists are again linked among each other. The last entry of the instFields points to the first entry of classFields and the last entry of classFields points to the first entry of constFields. With this structure searching for a certain field object will be highly efficient. Additionally two references are kept, which point to the first instance or class field which is a reference. For this purposes all fields, which denote references, are entered at the end of the list.

  • First instance field which is a reference → firstInstReference
  • First class field which is a reference → firstClassReference

The figure below shows an example for a class with two instance and two class fields as well as two constant fields. One of the instance fields is of a primitive type and one is a reference. Both class fields are of type reference.

Example of a class with six fields


For efficiency reasons all fields of an object or a class (defined as static) with the same size in memory should be placed together, which is done by sorting. For this purpose there are three static arrays in org.deepjava.classItems.Class. When parsing the fields their size and type is determined and entered according to their size into the appropriate array. Finally, the arrays are read out in proper order and the objects are entered in the lists as shown in the previous figure.

Constants

When parsing the constant pool all constants can be found in there. According to their tag different objects are created for them.

  • Integer, Long, Float, Double: new StdConstant, the object contains the value of the constant, the name is “#” and the type is set accordingly.
  • String: new StringLiteral, the object stores the string, the name is “” and the type is String.

When parsing the fields a check is made whether the attribute ConstantValue is set. This is the case for fields which are defined as final. If so, another object ConstField will be created which contains the name of the field, its type and a reference to an object Constant.
Let's take a look at an example:

  static final int a = 1;

For the class field a an object of type ConstField with the name “a” will be created. At the same time an object with the value of 1 of type StdConstant will be created. This object has the name “#”.
Important: The assignment of a value to a variable declared as final can be made when declaring it or in the constructor. This leads to the following cases.

class ClassA {
  static final int a;
  static final int b = 2000000;
  static final String str1 = "test1";
  static final String[] str2 = {"abc", "def"};
  static final Object obj = new Object();
  final int c = 3000000;
  final int d;
  static final double e = 0.1;
  static final double[] f = {0.5, 0,6};
 
  ClassA() {d = 4000000;}
 
  static {a = 2000000;}
}
 
interface ITest3 {
	int x = 100;
	String str3 = "test3";
	String[] str4 = {"a1", "a2"};
}
  • Case a: Attributes static and final are set. In the constant pool we have a=(class=ClassA, name=“a”, type='I'), it's not linked to a value. This only happens in <clinit>. There, a is linked to the object of type StdConstant with a value of 1'000'000. In field_info() of a the attribute ConstantValue is not set, therefore the dpfConst flag won't be set either. a goes into the list Class.classFields.
  • Case b: Is not listed as field at all. Present as constant only in the constant pool. An object NamedConst is created which points to an object StdConst with a value of 2000000. The dpfConst flag is set. This field goes into the list Class.constFields. Constant strings fall into the same category (case str1). For str1 an object StringLiteral will be created.
  • Case obj: Attributes static and final are set. In the constant pool we have c=(class=ClassA, name=“obj”, type='Object'). In field_info() of obj the attribute ConstantValue is not set, therefore the dpfConst flag won't be set either. obj goes into the list Class.classFields.
  • Case str2 and f: Attributes static and final are set. In field_info() the attribute ConstantValue is not set, therefore the dpfConst flag won't be set either. This field goes into the list Class.classFields.
  • Case c: final is set. In the constant pool we have c=(class=ClassA, name=“c”, type='I'), it's not linked to a value. That happens only in <init>. There, c is linked to the object of type StdConstant with a value of 3'000'000. In field_info() of c the attribute ConstantValue is not set, therefore the dpfConst flag is not set either. This field goes into the list Class.instFields.
  • Case d: final is set. In the constant pool we have d=(class=ClassA, name=“d”, type='I'), it's not linked to a value. That happens only in <init>. There, d is linked to the object of type StdConstant with a value of 4'000'000. In field_info() of d the attribute ConstantValue is not set, therefore the dpfConst flag is not set either. This field goes into the list Class.instFields.
  • Case e: same as case b

For interfaces we get:

  • Case x: same as case b
  • Case str3: same as case str1
  • Case str4: same as case str2

Important: When generating the SSA loading of a constant is translated with sCloadConst. If the constant is of type boolean, byte, short or int, which are not placed in the constant pool but in the code directly, a new object StdConstant must be created with the appropriate value and no name. In all other cases sCloadConst references the constant object built by the class file reader.

Methods

All reference types can have methods, even arrays as they inherit from java/lang/Object. The methods get sorted for building the type descriptors, see Type Descriptor.

Locals

Local variables within a method are dealt with in a separate section of the bytecode, the local variable table. First of all it contains information about the slot the variable occupies together with the range where the variable is defined. Different locals might occupy the same slot, even with different types.

dev/crosscompiler/cfr.txt · Last modified: 2022/12/20 11:20 by ursgraf