next up previous contents
Next: Exceptions and Errors Up: No Title Previous: Interpreter

Execution and Linking

The Java compiler does not generate a big executable file at compile time. Instead the compiler generates many small class files, one for each class, that will be interpreted during execution. This means that the compiler needs access to the class files involved at compile time and also that the JVM needs access to the same class files during execution. In this chapter we will describe the different stages in execution, namely start-up, loading ,linking and initialization.

JVM Start-up

The JVM will start executing an applicationgif by invoking the main method in the class file specified. This means that the class file that is retrieved from the command line needs to contain one and only one main method. For example, JAVAX can be invoked on a UNIX machine by typing:

    javax MakeEyesPop RightNow
The file MakeEyesPop.class is then loaded and the main method is executed. An array containing the string ``RightNow'' is passed as an argument. If more arguments are specified, they can be reached through the same array. The execution involves linking and creation of a frame to send to the Interpreter.

Loading

Loading refers to the process of finding the compiled form of a class (i.e. a class file) and constructing a Class object to represent the class. The first task is done by the ClassLoader who will search the current directory as well as the default Java directory. The ClassLoader will then store the name of the class file in an internal list to prevent from reloading the same file twice. The second task is performed by the Parser which will read and store the class file in a format understood by the rest of the JVM (i.e a ClassFile struct). This dynamic loading makes sure that only the class files that are really used will be loaded.

Linking

Linking is the process of taking a binary form of a class or interface type and combining it into the run-time state of the JVM, so that it can be executed. A class or interface is always loaded before it is linked. Linking involves: verification, preparation and optionally resolution.

Verification

  The verification process ensures that the binary representation of a class is structurally correct. A lot of checks have to be done at run-time since one cannot be sure that the class file has been generated by a trustworthy compiler like the one from Sun. Other compilers may be used as long as they generate bytecode that are within the limits of the class file format. The verification is also necessary since things might have happened to the class files used since the compilation. Consider the following:

Class A creates an object of class B and invokes one of its methods. After class A is compiled, the invoked method in class B is deleted for some reason. This does not change the fact that class A is already compiled and a class file is already generated. When the JVM tries to invoke the deleted method, in class B, it will throw a NoSuchMethodError and execution will be interrupted.

The verification process can be divided into four passes:

Pass 1
Overall class file format check
  1. Check magic_number (0xCAFEBABE).
  2. All recognized attributes must be of proper length. This check also ensures that the class file isn't truncated or doesn't have extra bytes added at its end.
  3. Check constant_pool entries to ensure that they don't contain unrecognized information.
Pass 2
Further checks on the class file format. No checks on the code attribute are done here.
  1. Check that final classes are not subclassed.
  2. Check that every class has a superclass (except Object).
  3. Check that every reference to the constant_pool is correct, i.e. to a correct entry and not out of bounds.
  4. Check all methods and fields. They must have correct format concerning names, descriptors and classes.
Pass 3
The Bytecode Verifier. Checks on the code array are done to ensure that:
  1. The operand stack is correct at all possible points in the code.
  2. Every local variable contains the right type when used.
  3. Every assignment is of correct type.
  4. All opcodes have appropriate operand types.
  5. Method invocations are correct.
Pass 4
Extensive code checks. Every time an instruction references a type the following must be done:
  1. Load definition.
  2. Check type.
  3. Initialize class.
Every time an instruction invokes a method or modifies a field the following must be correct:
  1. The field or method must exist.
  2. Descriptors must match.
  3. The method or field must be accessible according to the access_flags.
JAVAX performs some of the tests from pass one and two. No checks on the code are done.

Preparation

Preparation involves creating static fields for a class and initializing them to their default values, namely zero, null etc. No Java code is executed since the Java initialization methods are not run until later, in the initialization phase described below.

In our implementation we use a pointer static_p in each field_info which is set to null by the Parser. The struct field_info is part of our ClassFile struct and it contains information about a field. A field is essentially a variable so field_info includes descriptor as well as access flags.

The pointer static_p is used to access variables that are declared static. This is done since there may be only one copy of a static variable. The memory that the pointer refers to will be allocated at initialization time.

Initialization

  Initialization of a class consists of executing its static initializers as well as the initializers for the variables declared static. A static initializer is a block of code that is declared static. Before a class is initialized its super class must be initialized and so on. This procedure ends when class Object, or a class that are already initialized, is reached.

A class gets initialized by running the <clinit> method which is found in the class file providing that the class file contains static declarations. This is done in our implementation by a function called initialize_class which will parse every field_info and compute the object size. The object size is required in order to allocate an object. If a field is declared static we will allocate the memory in this function and set the pointer static_p to refer to it. Finally initialize_class will try to create a <clinit> frame and send it to the Interpreter if it was successful.

Not every class file contains a <clinit> method but every class file does contain an <init> method. These differ in the respect that the <init> method is always invoked when a new instance of a class is created. The <clinit> method is only invoked once. They unite in the respect that they are generated by the compiler and may not be designed by the programmer, hence the enclosing (<>).

Comparison to conventional linking

The JVM will only load class files when they are needed and will only initialize a class file if necessary. This means that a Java program will hopefully be more efficient in an interactive application since it is not clear at the beginning of the execution what will be needed. In conventional linking one will have to cover all the possibilities which leads to a very large executable file. Probably larger than necessary.

Another advantage becomes evident when class files are loaded over a network. A Java application is able to start executing when the class file containing the main method is loaded, hence start-up is fast. Conventional loading would require that every file that the program needs has to be loaded initially.

From Axis' point of view it is very attractive that Java is memory efficient. The memory in Etrax is limited and it would be nice if the JVM would eject class files that have not been used in awhile. JAVAX does not have this feature.

Run-time comparison

There are many similarities between the run-time system in Java and the one in Simula. The main features in an object-oriented run-time system are the descriptions of objects and methods (the frame and the object_info respectively). These help the run-time system to remember the overall state of the objects, as well as the methods. The internal design of these two posts are similar in Java and Simula.

The differences lie in the language specification which is reflected in the run-time system. There are three main differences:


next up previous contents
Next: Exceptions and Errors Up: No Title Previous: Interpreter

Magnus Hjersing
Wed Dec 18 18:44:00 MET 1996