Type resolution in JVM specification

| | bookmark | email
The JVM spec covers the following details about the lifecycle of a program:
  • VM start up
  • class and interface loading
  • linking
  • initialization
  • creation of new class instances
  • unloading of classes
  • VM exit
In this entry, we are interested in detailing how JVM is handling type resolution. Having the following code:
public class EntryPoint {
 public void someMethod() {
   ExternalDependecyClass.callMethod();
 }
}

import not.on.classpath.SomeClass

public class ExternalDependencyClass {
 public static void callMethod() {
   SomeClass cls= new SomeClass();
   // [...] work
 }
}
We are interested in finding out if the spec describes the behavior of the above code when the SomeClass is not found on the classpath (though the compilation was correctly performed). So, the class EntryPoint is loaded, and it must be initialized before it can be invoked, and a type (class or interface) must always be linked before it is initialized. Linking step involves:
  • verification: checks if the loaded representation is well formed, has a proper symbol table, the bytecode obeys the semantic requiremetns of the JVM
  • preparation: involves allocation of static storage and any data structures that are used internally by the virtual machine, such as method tables.
  • resolution (optional)
Resolution is the process of checking symbolic references from the loaded class to other classes and interfaces, by loading the other classes and interfaces that are mentioned and checking that the references are correct. The resolution step is optional at the time of initial linkage.
An implementation may resolve a symbolic reference from a class or interface that is being linked very early, even to the point of resolving all symbolic references from the classes and interfaces that are further referenced, recursively. (This resolution may result in errors from further loading and linking steps.)
This is an eager or static resolution implementation. There is also possible to do the resolution in a lazy way:
An implementation may instead choose to resolve a symbolic reference only when it is actually used; [...]. In this case, if the class had several symbolic references to another class, the references might be resolved one at a time or perhaps not at all, if these references were never used during execution of the program.
If the JVM implementation has chosen to use the eager/static type resolution strategy than an exception will be thrown before the program is executed. For the "lazy" type resolution JVMs, an exception will be thrown if and only if the symbolic reference is used. Now, you may wonder what is the solution. The only approach that will work in any JVM disregarding how the JVM implements the type resolution is to load the classes containing unsatisfied dependencies at the moment the execution needs them through reflection (for example if you are developing a library/framework than you will always have to do it this way because you don't know on what JVMs the library will be used). But, if you are developing an application that is known to run only on a JVM that used the "lazy" type resolution strategy than the initial code is safe. As a final note, SUN JVMs (at least 1.4 and 1.5) are using the lazy type resolution strategy.
category: