The Artima Developer Community
Table of Contents | Order the Book | Email | First Page | Previous | Next
Sponsored Link

Chapter 8 of Inside the Java Virtual Machine
The Linking Model
by Bill Venners

Page 1 of 20  >>

Advertisement

From the programmer's perspective, one of the most important aspects of Java's architecture to understand is the linking model. As mentioned in earlier chapters, Java's linking model allows you to design user-defined class loaders that extend your application in custom ways at run-time. Through user-defined class loaders, your application can load and dynamically link to classes and interfaces that were unknown or did not even exist when your application was compiled.

The engine that drives Java's linking model is the process of resolution. The previous chapter described all the various stages in the lifetime of a class, but didn't dive into the details of loading and resolution. This chapter looks at loading and resolution in depth, and shows how the process of resolution fits in with dynamic extension. It gives an overview of the linking model, explains constant pool resolution, describes method tables, shows how to write and use class loaders, and gives several examples.

Dynamic Linking and Resolution

When you compile a Java program, you get a separate class file for each class or interface in your program. Although the individual class files may appear to be independent, they actually harbor symbolic connections to one another and to the class files of the Java API. When you run your program, the Java virtual machine loads your program's classes and interfaces and hooks them together in a process of dynamic linking. As your program runs, the Java virtual machine builds an internal web of interconnected classes and interfaces.

A class file keeps all its symbolic references in one place, the constant pool. Each class file has a constant pool, and each class or interface loaded by the Java virtual machine has an internal version of its constant pool called the runtime constant pool. The runtime constant pool is an implementation-specific data structure that maps to the constant pool in the class file. Thus, after a type is initially loaded, all the symbolic references from the type reside in the type's runtime constant pool.

At some point during the running of a program, if a particular symbolic reference is to be used, it must be resolved. Resolution is the process of finding the entity identified by the symbolic reference and replacing the symbolic reference with a direct reference. Because all symbolic references reside in the constant pool, this process is often called constant pool resolution.

As described in Chapter 6, "The Java Class File," the constant pool is organized as a sequence of items. Each item has a unique index, much like an array element. A symbolic reference is one kind of item that may appear in the constant pool. Java virtual machine instructions that use a symbolic reference specify the index in the constant pool where the symbolic reference resides. For example, the getstatic opcode, which pushes the value of a static field onto the stack, is followed in the bytecode stream by an index into the constant pool. The constant pool entry at the specified index, a CONSTANT_Fieldref_info entry, reveals the fully qualified name of the class in which the field resides, and the name and type of the field.

Keep in mind that the Java virtual machine contains a separate runtime constant pool for each class and interface it loads. When an instruction refers to the fifth item in the constant pool, it is referring to the fifth item in the constant pool for the current class, the class that defined the method the Java virtual machine is currently executing.

Several instructions, from the same or different methods, may refer to the same constant pool entry, but each constant pool entry is resolved only once. After a symbolic reference has been resolved for one instruction, subsequent attempts to resolve it by other instructions take advantage of the hard work already done, and use the same direct reference resulting from the original resolution.

Linking involves not only the replacement of symbolic references with direct ones, it also involves checking for correctness and permission. As mentioned in Chapter 7, "The Lifetime of a Class," the checking of symbolic references for existence and access permission (one aspect of the full verification phase) is performed during resolution. For example, when a Java virtual machine resolves a getstatic instruction to a field of another class, the Java virtual machine checks to make sure that:

If any of these checks fail, an error is thrown and resolution fails. Otherwise, the symbolic reference is replaced by the direct reference and resolution succeeds.

As described in Chapter 7, "The Lifetime of a Class," different implementations of the Java virtual machine are permitted to perform resolution at different times during the execution of a program. An implementation may choose to link everything up front by following all symbolic references from the initial class, then all symbolic references from subsequent classes, until every symbolic reference has been resolved. In this case, the application would be completely linked before its main() method was ever invoked. This approach is called early resolution. Alternatively, an implementation may choose to wait until the very last minute to resolve each symbolic reference. In this case, the Java virtual machine would resolve a symbolic reference only when it is first used by the running program. This approach is called late resolution. Implementations may also use a resolution strategy in-between these two extremes.

Although a Java virtual machine implementation has some freedom in choosing when to resolve symbolic references, every Java virtual machine must give the outward impression that it uses late resolution. No matter when a particular Java virtual machine performs its resolution, it will always throw any error that results from attempting to resolve a symbolic reference at the point in the execution of the program where the symbolic reference was actually used for the first time. In this way, it will always appear to the user as if the resolution were late. If a Java virtual machine does early resolution, and during early resolution discovers that a class file is missing, it won't report the class file missing by throwing the appropriate error until later in the program when something in that class file is actually used. If the class is never used by the program, the error will never be thrown.

Page 1 of 20  >>

Table of Contents | Order the Book | Email | First Page | Previous | Next

Sponsored Links



Google
  Web Artima.com   
Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use