|
|
|
Advertisement
|
Phase two: Verification of symbolic references
Although phase one of verification likely takes place soon after the
JVM loads a class file, phase two is delayed until the bytecodes
contained in the class file actually are executed. Phase two verifies
symbolic references. A symbolic reference is a character
string that gives the name and possibly other information about the
referenced item -- enough information to uniquely identify a class,
field, or method. Thus, symbolic references to other classes give the
full name of the class. Symbolic references to the fields of other
classes give the class name, field name, and field descriptor. Symbolic
references to the methods of other classes give the class name, method
name, and method descriptor.
During phase two, the JVM follows the references from the class file being verified to the referenced class files, to make sure the references are correct. Because phase two has to look at other classes external to the class file being checked, phase two may require that new classes be loaded. Most JVM implementations will likely delay loading classes until they actually are used by the program.
If an implementation does load classes earlier -- perhaps in an attempt to speed up the loading process -- then it must still give the impression that it is loading classes as late as possible. If, for example, a Java virtual machine discovers during early loading that it can't find a certain referenced class, it doesn't throw a "class definition not found" error until (and unless) the referenced class is used for the first time by the running program.
Phase two and dynamic linking
Phase two of class-file verification is really just part of the process
of dynamic linking. When a class file is loaded, it contains symbolic
references to other classes and their fields and methods. Dynamic
linking is the process of resolving symbolic references into
direct references. As the JVM executes bytecodes and encounters an
opcode that, for the first time, uses a symbolic reference to another
class, the virtual machine must resolve the symbolic reference. The
virtual machine performs two basic tasks during resolution:
The virtual machine remembers the direct reference so that if it encounters the same reference again later, it can immediately use the direct reference without needing to spend time resolving the symbolic reference again.
When the Java virtual machine resolves a symbolic reference, phase two of the class-file verifier makes sure the reference is valid. If the reference is not valid -- for instance, if the class cannot be loaded or if the class exists but doesn't contain the referenced field or method -- the class-file verifier throws an error.
As an example, consider a class named Volcano. If a method
of class Volcano invokes a method in a class named
Lava, the name and descriptor of the method in
Lava are included as part of the binary data in the class
file for Volcano. So, during the course of execution when
Volcano's method first invokes Lava's method,
the JVM makes sure a method exists in class Lava that has
a name and descriptor that matches those expected by class
Volcano. If the symbolic reference (class name, method
name, and descriptor) is correct, the virtual machine replaces it with
a direct reference, such as a pointer, which it will use from then on.
But if the symbolic reference from class Volcano doesn't
match any method in class Lava, phase two verification
fails, and the JVM throws a "no such method" error.
Binary compatibility
The reason phase two of the class-file verifier must look at classes
that refer to one another to make sure they are compatible is because
Java programs are dynamically linked. Java compilers often will
recompile classes that depend on a class you have changed, and in so
doing, detect any incompatible changes at compile-time. But there may
be times when your compiler doesn't recompile a dependent class. For
example, if you are developing a large system, you will likely
partition the various parts of the system into packages. If you compile
each package separately, then a change to one class in a package would
likely cause a recompilation of affected classes within that same
package but not necessarily in any other package. Moreover, if you are
using someone else's packages, especially if your program downloads
class files from someone else's package across a network as it runs, it
may be impossible for you to check for compatibility at compile-time.
That's why phase two of the class-file verifier must check for
compatibility at runtime.
|
Sponsored Links
|