Contents | Prev | Next | IndexThe JavaTM Virtual Machine Specification


CHAPTER 5

Constant Pool Resolution


Java classes and interfaces are dynamically loaded (§2.16.2), linked (§2.16.3), and initialized (§2.16.4). Loading is the process of finding the binary form of a class or interface type with a particular name and constructing, from that binary form, a Class object to represent the class or interface. Linking is the process of taking a binary form of a class or interface type and combining it into the runtime state of the Java Virtual Machine so that it can be executed. Initialization of a class consists of executing its static initializers and the initializers for static fields declared in the class.

The Java Virtual Machine performs most aspects of these procedures through operations on a constant pool (§4.4), a per-type runtime data structure that serves many of the purposes of the symbol table of a conventional language. For example, Java Virtual Machine instructions that might otherwise have been designed to take immediate numeric or string operands instead fetch their operands from the constant pool. Classes, methods, and fields, whether referenced from Java Virtual Machine instructions or from other constant pool entries, are named using the constant pool.

A Java compiler does not presume to know the way in which a Java Virtual Machine lays out classes, interfaces, class instances, or arrays. References in the constant pool are always initially symbolic. At run time, the symbolic representation of the reference in the constant pool is used to work out the actual location of the referenced entity. The process of dynamically determining concrete values from symbolic references in the constant pool is known as constant pool resolution. Constant pool resolution may involve loading one or more classes or interfaces, linking several types, and initializing types. There are several kinds of constant pool entries, and the details of resolution differ with the kind of entry to be resolved.

Individual Java Virtual Machine instructions that reference entities in the constant pool are responsible for resolving the entities they reference. Constant pool entries that are referenced from other constant pool entries are resolved when the referring entry is resolved.

A given constant pool entry may be referred to from any number of Java Virtual Machine instructions or other constant pool entries; thus, constant pool resolution can be attempted on a constant pool entry that is already resolved. An attempt to resolve a constant pool entry that has already been successfully resolved always succeeds trivially, and always results in the same entity produced by the initial resolution of that entry.

Constant pool resolution is normally initiated by the execution of a Java Virtual Machine instruction that references the constant pool. Rather than give the full description of the resolution process performed by Java Virtual Machine instructions in their individual descriptions, we will use this chapter to summarize the constant pool resolution process. We will specify the errors that must be detected when resolving each kind of constant pool entry, the order in which those errors must be responded to, and the errors thrown in response.

When referenced from the context of certain Java Virtual Machine instructions, additional constraints are put on linking operations. For instance, the getfield instruction requires not only that the constant pool entry for the field it references can be successfully resolved, but also that the resolved field is not a class (static) field. If it is a class field, an exception must be thrown. Linking exceptions that are specific to the execution of a particular Java Virtual Machine instruction are given in the description of that instruction and are not covered in this general discussion of constant pool resolution. Note that such exceptions, although described as part of the execution of Java Virtual Machine instructions rather than constant pool resolution, are still properly considered failure of the linking phase of Java Virtual Machine execution.

The Java Virtual Machine specification documents and orders all exceptions that can arise as a result of constant pool resolution. It does not mandate how they should be detected, only that they must be. In addition, as mentioned in §6.3, any of the virtual machine errors listed as subclasses of VirtualMachineError may be thrown at any time during constant pool resolution.


5.1 Class and Interface Resolution

A constant pool entry tagged as CONSTANT_Class (§4.4.1) represents a class or interface. Various Java Virtual Machine instructions reference CONSTANT_Class entries in the constant pool of the class that is current upon their execution (§3.6). Several other kinds of constant pool entries (§4.4.2) reference CONSTANT_Class entries and cause those class or interface references to be resolved when the referencing entries are resolved. For instance, before a method reference (a CONSTANT_Methodref constant pool entry) can be resolved, the reference it makes to the class of the method (via the class_index item of the constant pool entry) must first be resolved.

If a class or interface has not been resolved already, the details of the resolution process depend on what kind of entity is represented by the CONSTANT_Class entry being resolved. Array classes are handled differently from non-array classes and from interfaces. Details of the resolution process also depend on whether the reference prompting the resolution of this class or interface is from a class or interface that was loaded using a class loader (§2.16.2).

The name_index item of a CONSTANT_Class constant pool entry is a reference to a CONSTANT_Utf8 constant pool entry (§4.4.7) for a UTF-8 string that represents the fully qualified name (§2.7.9) of the class or interface to be resolved. What kind of entity is represented by a CONSTANT_Class constant pool entry, and how to resolve that entry, is determined as follows:

5.1.1 Current Class or Interface Not Loaded by a Class Loader

If a class or interface that has been loaded, and that was not loaded using a class loader, references a non-array class or interface C, then the following steps are performed to resolve the reference to C:

  1. The class or interface C and its superclasses are first loaded (§2.16.2).
  2. If class or interface C has not been loaded yet, the Java Virtual Machine will search for a file C.class and attempt to load class or interface C from that file. Note that there is no guarantee that the file C.class will actually contain the class or interface C, or that the file C.class is even a valid class file. It is also possible that class or interface C might have already been loaded, but not yet initialized. This phase of loading must detect the following errors:
  3. If the superclass of the class being loaded has not yet been loaded, it is loaded using this step 1 recursively. Loading a superclass must detect any of the errors in step 1a, where this superclass is considered to be the class being loaded. Note that all interfaces must have java.lang.Object as their superclass, which must already have been loaded.
  4. If loading class C and its superclasses was successful, the superclass (and thus its superclasses, if any) of class C is linked and initialized by applying steps -2-4 recursively.
  5. The class C is linked (§2.16.3), that is, it is verified (§4.9) and prepared.
  6. First, the class or interface C is verified to ensure that its binary representation is structurally valid (passes 2 and 3 of §4.9.1).1 Verification may itself cause classes and interfaces to be loaded, but not initialized (to avoid circularity), using the procedure in step 1.
  7. If the class file for class or interface C is successfully verified, the class or interface is prepared. Preparation involves creating the static fields for the class or interface and initializing those fields to their standard default values (§2.5.1). Preparation should not be confused with the execution of static initializers (§2.11); unlike execution of static initializers, preparation does not require the execution of any Java code. During preparation:
  8. Certain checks that are specific to individual Java Virtual Machine instructions, but that are logically related to this phase of constant pool resolution, are described in the documentation of those instructions. For instance, the getfield instruction resolves its field reference, and only afterward checks to see whether that field is an instance field (that is, it is not static). Such exceptions are still considered and documented to be linking, not runtime, exceptions.
  9. Next, the class is initialized. Details of the initialization procedure are given in §2.16.5 and in The Java Language Specification.
  10. Finally, access permissions to the class being resolved are checked:
If none of the preceding errors were detected, constant pool resolution of the class or interface reference must have completed successfully. However, if an error was detected, one of the following must be true.

In either case, the resolution fails, and the class or interface attempting to perform the resolution is prohibited from accessing the referenced class or interface.

5.1.2 Current Class or Interface Loaded by a Class Loader

If a class or interface, loaded using a class loader, references a non-array class or interface C, then that same class loader is used to load C. The loadClass method of that class loader is invoked on the fully qualified path name (§2.7.9) of the class to be resolved. The value returned by the loadClass method is the resolved class. The remainder of the section describes this process in more detail.

Every class loader is an instance of a subclass of the abstract class ClassLoader. Applications implement subclasses of ClassLoader in order to extend the manner in which the Java Virtual Machine dynamically loads classes. Class loaders can be used to create classes that originate from sources other than files. For example, a class could be downloaded across a network, it could be generated on the fly, or it could be decrypted from a scrambled file.

The Java Virtual Machine invokes the loadClass method of a class loader in order to cause it to load (and optionally link and initialize) a class. The first argument to loadClass is the fully qualified name of the class to be loaded. The second argument is a boolean. The value false indicates that the specified class must be loaded, but not linked or initialized; the value true indicates the class must be loaded, linked, and initialized.

Implementations of class loaders are required to keep track of which classes they have already loaded, linked, and initialized:2

When the class loader's loadClass method is invoked with the name of a class or interface that it has not yet loaded, the class loader must perform one of the following two operations in order to load the class or interface:

After the class or interface and its superclasses have been loaded successfully, if the second argument to loadClass is true the class or interface is linked and initialized. This second argument is always true if the class loader is being called upon to resolve an entry in the constant pool of a class or interface. The class loader links and initializes a class or interface by invoking the method resolveClass in the class ClassLoader. Linking and initializing a class or interface created by a class loader is very similar to linking and initializing a class or interface without a class loader (steps 2-4 of §5.1.1):

First, the superclass of the class or interface is linked and initialized by calling the loadClass method of the class loader with the fully qualified name of the superclass as the first argument, and true as the second argument. Linking and initialization may result in the superclass's own superclass being linked and initialized. Linking and initialization of a superclass must detect any of the errors of step 3 of §5.1.1.

Next, the bytecode verifier is run on the class or interface being linked and initialized. The verifier may itself need classes or interfaces to be loaded, and if so, it loads them by invoking the loadClass method of the same class loader with the second argument being false. Since verification may itself cause classes or interfaces to be loaded (but not linked or initialized, to avoid circularity), it must detect the errors of step 1 of §5.1.1 for any classes or interfaces it attempts to load. Running the verifier may also cause the errors of step 3a of §5.1.1.

If the class file is successfully verified, the class or interface is then prepared (step 3b of §5.1.1) and initialized (step 4 of §5.1.1).

Finally, access permissions to the class or interface are checked (step 5 of §5.1.1). If the current class or interface does not have permission to access the class being resolved, class resolution throws an IllegalAccessError exception.

If none of the preceding errors were detected, loading, linking, and initialization of the class or interface must have completed successfully.

5.1.3 Array Classes

A constant pool entry tagged as CONSTANT_Class (§4.4.1) represents an array class if the first character of the UTF-8 string (§4.4.7) referenced by the name_index item of that constant pool entry is a left bracket ("["). The number of initial consecutive left brackets in the name represents the number of dimensions of the array class. Following the one or more initial consecutive left brackets is a field descriptor (§4.3.2) representing either a primitive type or a non-array reference type; this field descriptor represents the base type of the array class.

The following steps are performed to resolve an array class referenced from the constant pool of a class or interface:

  1. Determine the number of dimensions of the array class and the field descriptor that represents the base type of the array class.
  2. Determine the base type of the array class:
  1. If an array class representing the same base type and the same number of dimensions has already been created, the result of the resolution is that array class. Otherwise, a new array class representing the indicated base type and number of dimensions is created.

5.2 Field and Method Resolution

A constant pool entry tagged as CONSTANT_Fieldref (§4.4.2) represents a class or instance variable (§2.9) or a (constant) field of an interface (§2.13.4). Note that interfaces do not have instance variables. A constant pool entry tagged as CONSTANT_Methodref (§4.4.2) represents a method of a class (a static method) or of a class instance (an instance method). References to interface methods are made using CONSTANT_InterfaceMethodref constant pool entries; resolution of such entries is described in §5.3.

To resolve a field reference or a method reference, the CONSTANT_Class (§4.4.1) entry representing the class of which the field or method is a member must first be successfully resolved (§5.1). Thus, any exception that can be thrown when resolving a CONSTANT_Class constant pool entry can also be thrown as a result of resolving a CONSTANT_Fieldref or CONSTANT_Methodref entry. If the CONSTANT_Class entry representing the class or interface can be successfully resolved, exceptions relating to the linking of the method or field itself can be thrown. When resolving a field reference:

If resolving a method:


5.3 Interface Method Resolution

A constant pool entry tagged as CONSTANT_InterfaceMethodref (§4.4.2) represents a call to an instance method declared by an interface. Such a constant pool entry is resolved by converting it into a machine-dependent internal format. No error or exception is possible except for those documented in §6.3.


5.4 String Resolution

A constant pool entry tagged as CONSTANT_String (§4.4.3) represents an instance of a string literal (§2.3), that is, a literal of the built-in type java.lang.String. The Unicode characters (§2.1) of the string literal represented by the CONSTANT_String entry are found in the CONSTANT_Utf8 (§4.4.7) constant pool entry that the CONSTANT_String entry references.

The Java language requires that identical string literals (that is, literals that contain the same sequence of Unicode characters) must reference the same instance of class String. In addition, if the method intern is called on any string, the result is a reference to the same class instance that would be returned if that string appeared as a literal. Thus,

    ("a" + "b" + "c").intern() == "abc"

must have the value true.3

To resolve a constant pool entry tagged CONSTANT_String, the Java Virtual Machine examines the series of Unicode characters represented by the UTF-8 string that the CONSTANT_String entry references.

No error or exception is possible during string resolution except for those documented in §6.3.


5.5 Resolution of Other Constant Pool Items

Constant pool entries that are tagged CONSTANT_Integer or CONSTANT_Float (§4.4.4), CONSTANT_Long or CONSTANT_Double (§4.4.5) all have values that are directly represented within the constant pool. Their resolution cannot throw exceptions except for those documented in §6.3.

Constant pool entries that are tagged CONSTANT_NameAndType (§4.4.6), and CONSTANT_Utf8 (§4.4.7) are never resolved directly. They are only referenced directly or indirectly by other constant pool entries.


1 Sun's JDK release 1.0.2 only verifies class files that have class loaders; it assumes that class files loaded locally are trusted and do not need verification.

2 Future implementations may change the API between the Java Virtual Machine and the class ClassLoader. Specifically, the Java Virtual Machine rather than the class loader will keep track of which classes and interfaces have been loaded by a particular class loader. One possibility is that the loadClass method will be called with a single argument indicating the class or interface to be loaded. The virtual machine will handle the details of linking and initialization and ensure that the class loader is not invoked with the same class or interface name multiple times.

3 String literal resolution is not implemented correctly in Sun's JDK release 1.0.2. In that implementation of the Java Virtual Machine, resolving a CONSTANT_String in the constant pool always allocates a new string. Two string literals in two different classes, even if they contained the identical sequence of characters, would never be == to each other. A string literal could never be == to a result of the intern method.


Contents | Prev | Next | Index

Java Virtual Machine Specification

Copyright © 1996, 1997 Sun Microsystems, Inc. All rights reserved
Please send any comments or corrections to jvm@java.sun.com