This specification is not final and is subject to change. Use is subject to license terms.

JVM Types Cleanup

Changes to the Java® Virtual Machine Specification • Version 20-internal-adhoc.dlsmith.20220830

This document describes changes to the Java Virtual Machine Specification, as modified by the Better-defined JVM Class File Validation JEP, to clean up the specification's treatment of types. These changes facilitate introducing new typing features to support primitive objects.

All changes are presentational, with no intention to change the behavior of JVM implementations.

Most changes fall into one of the following areas:

Changes are described with respect to existing sections of the JVM Specification. New text is indicated like this and deleted text is indicated like this. Explanation and discussion, as needed, is set aside in grey boxes.

To do: accessibility of array type receivers.

Chapter 2: The Structure of the Java Virtual Machine

2.2 Data Types

Like the Java programming language, the The Java Virtual Machine operates on two kinds of types: primitive types and reference types. There are, correspondingly, two kinds of values that can be stored in variables, passed as arguments, returned by methods, and operated upon: primitive values and reference values.

The Java Virtual Machine expects that nearly all type checking is done prior to run time, typically by a compiler, and does not have to be done by the Java Virtual Machine itself. Values of primitive types need not be tagged or otherwise be inspectable to determine their types at run time, or to be distinguished from values of reference types. Instead, the instruction set of the Java Virtual Machine distinguishes its operand types using instructions intended to operate on values of specific types. For instance, iadd, ladd, fadd, and dadd are all Java Virtual Machine instructions that add two numeric values and produce numeric results, but each is specialized for its operand type: int, long, float, and double, respectively. For a summary of type support in the Java Virtual Machine instruction set, see 2.11.1.

The Java Virtual Machine contains explicit support for objects. An object is either a dynamically allocated class instance or an array. A reference to an object is considered to have Java Virtual Machine type reference. References are polymorphic: a single reference may also be a value of multiple class types, interface types, or array types. Values of type reference can be thought of as pointers to objects. More than one reference to an object may exist. Objects are always operated on, passed, and tested via values of type reference.

2.6 Frames

2.6.1 Local Variables

Each frame (2.6) contains an array of variables known as its local variables. The length of the local variable array of a frame is determined at compile-time and supplied in the binary representation of a class or interface along with the code for the method associated with the frame (4.7.3).

A single local variable can hold a value of type boolean, byte, char, short, int, float, reference, or returnAddress. A pair of local variables can hold a value of type long or double.

Local variables are addressed by indexing. The index of the first local variable is zero. An integer is considered to be an index into the local variable array if and only if that integer is between zero and one less than the size of the local variable array.

A value of type long or type double occupies two consecutive local variables. Such a value may only be addressed using the lesser index. For example, a value of type double stored in the local variable array at index n actually occupies the local variables with indices n and n+1; however, the local variable at index n+1 cannot be loaded from. It can be stored into. However, doing so invalidates the contents of local variable n.

The Java Virtual Machine does not require n to be even. In intuitive terms, values of types long and double need not be 64-bit aligned in the local variables array. Implementors are free to decide the appropriate way to represent such values using the two local variables reserved for the value.

The Java Virtual Machine uses local variables to pass parameters on method invocation. On class method invocation, any parameters are passed in consecutive local variables starting from local variable 0. On instance method invocation, local variable 0 is always used to pass a reference to the object on which the instance method is being invoked (this in the Java programming language). Any parameters are subsequently passed in consecutive local variables starting from local variable 1.

2.11 Instruction Set Summary

2.11.1 Types and the Java Virtual Machine

Most of the instructions in the Java Virtual Machine instruction set encode type information about the operations they perform. For instance, the iload instruction (6.5.iload) loads the contents of a local variable, which must be an int, onto the operand stack. The fload instruction (6.5.fload) does the same with a float value. The two instructions may have identical implementations, but have distinct opcodes.

For the majority of typed instructions, the instruction type is represented explicitly in the opcode mnemonic by a letter: i for an int operation, l for long, s for short, b for byte, c for char, f for float, d for double, and a for reference. Some instructions for which the type is unambiguous do not have a type letter in their mnemonic. For instance, arraylength always operates on an object that is an array. Some instructions, such as goto, an unconditional control transfer, do not operate on typed operands.

Given the Java Virtual Machine's one-byte opcode size, encoding types into opcodes places pressure on the design of its instruction set. If each typed instruction supported all of the Java Virtual Machine's run-time data types, there would be more instructions than could be represented in a byte. Instead, the instruction set of the Java Virtual Machine provides a reduced level of type support for certain operations. In other words, the instruction set is intentionally not orthogonal. Separate instructions can be used to convert between unsupported and supported data types as necessary.

Table 2.11.1-A summarizes the type support in the instruction set of the Java Virtual Machine. A specific instruction, with type information, is built by replacing the T in the instruction template in the opcode column by the letter in the type column. If the type column for some instruction template and type is blank, then no instruction exists supporting that type of operation. For instance, there is a load instruction for type int, iload, but there is no load instruction for type byte.

Note that most instructions in Table 2.11.1-A do not have forms for the integral types byte, char, and short. None have forms for the boolean type. A compiler encodes loads of literal values of types byte and short using Java Virtual Machine instructions that sign-extend those values to values of type int at compile-time or run-time. Loads of literal values of types boolean and char are encoded using instructions that zero-extend the literal to a value of type int at compile-time or run-time. Likewise, loads from arrays of values of type boolean, byte, short, and char are encoded using Java Virtual Machine instructions that sign-extend or zero-extend the values to values of type int. Whenever values of types byte and short are loaded onto the operand stack, they are implicitly converted by sign extension to values of type int. Similarly, whenever values of types boolean and char are loaded onto the operand stack, they are implicitly converted by zero extension to values of type int. Thus, most operations on values originally of actual types boolean, byte, char, and short are correctly performed by instructions operating on values of computational type int.

Table 2.11.1-A. Type support in the Java Virtual Machine instruction set

opcode byte short int long float double char reference
Tipush bipush sipush
Tconst iconst lconst fconst dconst aconst
Tload iload lload fload dload aload
Tstore istore lstore fstore dstore astore
Tinc iinc
Taload baload saload iaload laload faload daload caload aaload
Tastore bastore sastore iastore lastore fastore dastore castore aastore
Tadd iadd ladd fadd dadd
Tsub isub lsub fsub dsub
Tmul imul lmul fmul dmul
Tdiv idiv ldiv fdiv ddiv
Trem irem lrem frem drem
Tneg ineg lneg fneg dneg
Tshl ishl lshl
Tshr ishr lshr
Tushr iushr lushr
Tand iand land
Tor ior lor
Txor ixor lxor
i2T i2b i2s i2l i2f i2d
l2T l2i l2f l2d
f2T f2i f2l f2d
d2T d2i d2l d2f
Tcmp lcmp
Tcmpl fcmpl dcmpl
Tcmpg fcmpg dcmpg
if_TcmpOP if_icmpOP if_acmpOP
Treturn ireturn lreturn freturn dreturn areturn

The mapping between Java Virtual Machine actual original types and Java Virtual Machine computational types is summarized by Table 2.11.1-B.

Certain Java Virtual Machine instructions such as pop and swap operate on the operand stack without regard to type; however, such instructions are constrained to use only on values of certain categories of computational types, also given in Table 2.11.1-B.

Table 2.11.1-B. Actual Original and Computational types in the Java Virtual Machine

Actual Original type Computational type Category
boolean int 1
byte int 1
char int 1
short int 1
int int 1
float float 1
reference reference 1
returnAddress returnAddress 1
long long 2
double double 2

2.11.2 Load and Store Instructions

The load and store instructions transfer values between the local variables (2.6.1) and the operand stack (2.6.2) of a Java Virtual Machine frame (2.6):

Instructions that access fields of objects and elements of arrays (2.11.5) also transfer data to and from the operand stack.

Instruction mnemonics shown above with trailing letters between angle brackets (for instance, iload_<n>) denote families of instructions (with members iload_0, iload_1, iload_2, and iload_3 in the case of iload_<n>). Such families of instructions are specializations of an additional generic instruction (iload) that takes one operand. For the specialized instructions, the operand is implicit and does not need to be stored or fetched. The semantics are otherwise the same (iload_0 means the same thing as iload with the operand 0). The letter between the angle brackets specifies the type of the implicit operand for that family of instructions: for <n>, a nonnegative integer; for <i>, an int; for <l>, a long; for <f>, a float; and for <d>, a double. Forms for type int are used in many cases to perform operations on values of type byte, char, and short (2.11.1).

This notation for instruction families is used throughout this specification.

2.11.8 Method Invocation and Return Instructions

The following five instructions invoke methods:

The method return instructions, which are distinguished by return type, are ireturn (used to return values of type boolean, byte, char, short, or int), lreturn, freturn, dreturn, and areturn. In addition, the return instruction is used to return from methods declared to be void.

Chapter 4: The class File Format

4.3 Descriptors

A descriptor is a string representing the type of a field or method. Descriptors are represented in the class file format using modified UTF-8 strings (4.4.7) and thus may be drawn, where not further constrained, from the entire Unicode codespace.

4.3.1 Grammar Notation

Descriptors are specified using a grammar. The grammar is a set of productions that describe how sequences of characters can form syntactically correct descriptors of various kinds. Terminal symbols of the grammar are shown in fixed width font, and should be interpreted as ASCII characters. Nonterminal symbols are shown in italic type. The definition of a nonterminal is introduced by the name of the nonterminal being defined, followed by a colon. One or more alternative definitions for the nonterminal then follow on succeeding lines.

The syntax {x} on the right-hand side of a production denotes zero or more occurrences of x.

The phrase (one of) on the right-hand side of a production signifies that each of the terminal symbols on the following line or lines is an alternative definition.

4.3.2 Field Descriptors

A field descriptor represents the type of a class, instance field, parameter, value, or local variable.

FieldDescriptor:
FieldType
FieldType:
BaseType
ObjectType ClassType
ArrayType
BaseType:
(one of)
B C D F I J S Z
ObjectType: ClassType:
L ClassName ;
ArrayType:
[ ComponentType
ComponentType:
FieldType

The characters of BaseType, the L and ; of ObjectType, and the [ of ArrayType are all ASCII characters.

ClassName represents a binary class or interface name encoded in internal form (4.2.1).

A field descriptor mentions a class or interface name if the name appears as a ClassName in the descriptor. This includes a ClassName nested in the ComponentType of an ArrayType.

This definition of mentions allows us to eliminate boilerplate in a handful of other sections and gives us a single location to identify the classes that are subject to loading constraints, resolution, etc. The definition is flexible enough to support new kinds of types that may be added in the future.

The interpretation of field descriptors as types is shown in Table 4.3-A. See 2.2, 2.3, and 2.4 for the meaning of these types.

A field descriptor representing an array type is valid only if it represents a type with 255 or fewer dimensions.

Table 4.3-A. Interpretation of field descriptors

FieldType term Type Interpretation
B byte signed byte
C char Unicode character code point in the Basic Multilingual Plane, encoded with UTF-16
D double double-precision floating-point value
F float single-precision floating-point value
I int integer
J long long integer
L ClassName ; reference Named class or interface type an instance of class ClassName
S short signed short
Z boolean true or false
[ reference Array of given component type one array dimension

The field descriptor of an instance variable of type int is simply I.

The field descriptor of an instance variable of type Object is Ljava/lang/Object;. Note that the internal form of the binary name for class Object is used.

The field descriptor of an instance variable of the multidimensional array type double[][][] is [[[D.

The "Interpretation" column of Table 4.3-A is redundant; these details are better left to sections 2.2, 2.3 and 2.4.

4.3.3 Method Descriptors

A method descriptor contains zero or more parameter descriptors, representing the types of parameters that the method takes, and a return descriptor, representing the type of the value (if any) that the method returns.

MethodDescriptor:
( {ParameterDescriptor} ) ReturnDescriptor
ParameterDescriptor:
FieldType
ReturnDescriptor:
FieldType
VoidDescriptor
VoidDescriptor:
V

The character V indicates that the method returns no value (its result is void).

A method descriptor mentions a class or interface name if the name appears as a ClassName in the FieldType of a parameter descriptor or return descriptor.

The method descriptor for the method:

Object m(int i, double d, Thread t) {...}

is:

(IDLjava/lang/Thread;)Ljava/lang/Object;

Note that the internal forms of the binary names of Thread and Object are used.

A method descriptor is valid only if it represents method parameters with a total length of 255 or less, where that length includes the contribution for this in the case of instance or interface method invocations. The total length is calculated by summing the contributions of the individual parameters, where a parameter of type long or double contributes two units to the length and a parameter of any other type contributes one unit.

A method descriptor is the same whether the method it describes is a class method or an instance method. Although an instance method is passed this, a reference to the object on which the method is being invoked, in addition to its intended arguments, that fact is not reflected in the method descriptor. The reference to this is passed implicitly by the Java Virtual Machine instructions which invoke instance methods (2.6.1, 4.11).

4.7 Attributes

4.7.16 The RuntimeVisibleAnnotations Attribute

4.7.16.1 The element_value structure

...

class_info_index

The class_info_index item denotes a class literal as the value of this element-value pair.

The class_info_index item should be a valid index into the constant_pool table. The constant_pool entry at that index should be a CONSTANT_Utf8_info structure (4.4.7) representing a return descriptor (4.3.3). The return descriptor gives the type corresponding to the class literal represented by this element_value structure. Types correspond to class literals as follows:

  • For a class literal C.class, where C is the name of a class, or interface, or array type, the corresponding type is C. The return descriptor in the constant_pool should be an ObjectType or an ArrayType a ClassType.

  • For a class literal T[].class, where T[] is an array type, the corresponding type is T[]. The return descriptor in the constant_pool should be an ArrayType.

  • For a class literal p.class, where p is the name of a primitive type, the corresponding type is p. The return descriptor in the constant_pool should be a BaseType character.

  • For a class literal void.class, the corresponding type is void. The return descriptor in the constant_pool should be V.

For example, the class literal Object.class corresponds to the type Object, so the constant_pool entry is Ljava/lang/Object;, whereas the class literal int.class corresponds to the type int, so the constant_pool entry is I.

The class literal void.class corresponds to void, so the constant_pool entry is V, whereas the class literal Void.class corresponds to the type Void, so the constant_pool entry is Ljava/lang/Void;.

...

4.9 Constraints on Java Virtual Machine Code

4.9.2 Structural Constraints

The structural constraints on the code in a class file specify constraints on relationships between Java Virtual Machine instructions, exception handlers, and stack maps. The structural constraints are as follows:

...

Chapter 5: Loading, Linking, and Initializing

5.1 The Run-Time Constant Pool

The Java Virtual Machine maintains a run-time constant pool for each class and interface (2.5.5). This data structure serves many of the purposes of the symbol table of a conventional programming language implementation. The constant_pool table in the binary representation of a class or interface (4.4) is used to construct the run-time constant pool upon class or interface creation (5.3).

There are two kinds of entry in the run-time constant pool: symbolic references, which may later be resolved (5.4.3), and static constants, which require no further processing.

The symbolic references in the run-time constant pool are derived from entries in the constant_pool table in accordance with the structure of each entry:

The static constants in the run-time constant pool are also derived from entries in the constant_pool table in accordance with the structure of each entry:

The remaining structures in the constant_pool table - the descriptive structures CONSTANT_NameAndType_info, CONSTANT_Module_info, and CONSTANT_Package_info, and the foundational structure CONSTANT_Utf8_info - are only used indirectly when constructing the run-time constant pool. No entries in the run-time constant pool correspond directly to these structures.

Some entries in the run-time constant pool are loadable, which means:

An entry in the run-time constant pool is loadable if it is derived from an entry in the constant_pool table that is loadable (see Table 4.4-C). Accordingly, the following entries in the run-time constant pool are loadable:

5.3 Creation and Loading

Creation of a class or interface C denoted by the name N consists of the construction in the method area of the Java Virtual Machine (2.5.4) of an implementation-specific internal representation of C. Class or interface creation is triggered by another class or interface D, which references C through its run-time constant pool. Class or interface creation may also be triggered by D invoking methods in certain Java SE Platform class libraries (2.12) such as reflection.

If C is not an array class, it is created by loading a binary representation of C (4) using a class loader. Array classes do not have an external binary representation; they are created by the Java Virtual Machine rather than by a class loader.

A class or interface is created by loading a binary representation of the class or interface (4) using a class loader. There are two kinds of class loaders: the bootstrap class loader supplied by the Java Virtual Machine, and user-defined class loaders. Every user-defined class loader is an instance of a subclass of the abstract class ClassLoader. Applications employ user-defined class loaders in order to extend the manner in which the Java Virtual Machine dynamically loads and thereby creates classes. User-defined class loaders can be used to create classes that originate from user-defined sources. For example, a class could be downloaded across a network, generated on the fly, or extracted from an encrypted file.

A class loader L may create C by defining it directly or by delegating to another class loader. If L creates C directly, we say that L defines C or, equivalently, that L is the defining loader of C.

When one class loader delegates to another class loader, the loader that initiates the loading is not necessarily the same loader that completes the loading and defines the class. If L creates C, either by defining it directly or by delegation, we say that L initiates loading of C or, equivalently, that L is an initiating loader of C.

At run time, a class or interface is determined not by its name alone, but by a pair: its binary name (4.2.1) and its defining class loader. Each such class or interface belongs to a single run-time package. The run-time package of a class or interface is determined by the package name and defining class loader of the class or interface.

The Java Virtual Machine uses one of three two procedures to create class or interface C denoted by N:

If an error occurs during class loading, then an instance of a subclass of LinkageError must be thrown at a point in the program that (directly or indirectly) uses the class or interface being loaded.

If the Java Virtual Machine ever attempts to load a class C during verification (5.4.1) or resolution (5.4.3) (but not initialization (5.5)), and the class loader that is used to initiate loading of C throws an instance of ClassNotFoundException, then the Java Virtual Machine must throw an instance of NoClassDefFoundError whose cause is the instance of ClassNotFoundException.

(A subtlety here is that recursive class loading to load superclasses is performed as part of resolution (5.3.5, step 3). Therefore, a ClassNotFoundException that results from a class loader failing to load a superclass must be wrapped in a NoClassDefFoundError.)

A well-behaved class loader should maintain three properties:

We will sometimes represent a class or interface using the notation <N, Ld>, where N denotes the name of the class or interface and Ld denotes the defining loader of the class or interface.

We will also represent a class or interface using the notation NLi, where N denotes the name of the class or interface and Li denotes an initiating loader of the class or interface.

5.3.1 Loading Using the Bootstrap Class Loader

The following steps are used to load and thereby create the nonarray class or interface C denoted by N using the bootstrap class loader.

First, the Java Virtual Machine determines whether the bootstrap class loader has already been recorded as an initiating loader of a class or interface denoted by N. If so, this class or interface is C, and no class creation is necessary.

Otherwise, the Java Virtual Machine passes the argument N to an invocation of a method on the bootstrap class loader to search for a purported representation of C in a platform-dependent manner. Typically, a class or interface will be represented using a file in a hierarchical file system, and the name of the class or interface will be encoded in the pathname of the file.

Note that there is no guarantee that a purported representation found is valid or is a representation of C. This phase of loading must detect the following error:

Then the Java Virtual Machine attempts to derive a class denoted by N using the bootstrap class loader from the purported representation using the algorithm found in 5.3.5. That class is C.

5.3.2 Loading Using a User-defined Class Loader

The following steps are used to load and thereby create the nonarray class or interface C denoted by N using a user-defined class loader L.

First, the Java Virtual Machine determines whether L has already been recorded as an initiating loader of a class or interface denoted by N. If so, this class or interface is C, and no class creation is necessary.

Otherwise, the Java Virtual Machine invokes loadClass(N) on L. The value returned by the invocation is the created class or interface C. The Java Virtual Machine then records that L is an initiating loader of C (5.3.4). The remainder of this section describes this process in more detail.

When the loadClass method of the class loader L is invoked with the name N of a class or interface C to be loaded, L must perform one of the following two operations in order to load C:

  1. The class loader L can create an array of bytes representing C as the bytes of a ClassFile structure (4.1); it then must invoke the method defineClass of class ClassLoader. Invoking defineClass causes the Java Virtual Machine to derive a class or interface denoted by N using L from the array of bytes using the algorithm found in 5.3.5.

  2. The class loader L can delegate the loading of C to some other class loader L'. This is accomplished by passing the argument N directly or indirectly to an invocation of a method on L' (typically the loadClass method). The result of the invocation is C.

In either (1) or (2), if the class loader L is unable to load a class or interface denoted by N for any reason, it must throw an instance of ClassNotFoundException.

Since JDK 1.1, Oracle’s Java Virtual Machine implementation has invoked the loadClass method of a class loader in order to cause it to load a class or interface. The argument to loadClass is the name of the class or interface to be loaded. There is also a two-argument version of the loadClass method, where the second argument is a boolean that indicates whether the class or interface is to be linked or not. Only the two-argument version was supplied in JDK 1.0.2, and Oracle’s Java Virtual Machine implementation relied on it to link the loaded class or interface. From JDK 1.1 onward, Oracle’s Java Virtual Machine implementation links the class or interface directly, without relying on the class loader.

5.3.3 Creating Array Classes

The following steps are used to create the array class C denoted by N using class loader L. Class loader L may be either the bootstrap class loader or a user-defined class loader.

If L has already been recorded as an initiating loader of an array class with the same component type as N, that class is C, and no array class creation is necessary.

Otherwise, the following steps are performed to create C:

  1. If the component type is a reference type, the algorithm of this section (5.3) is applied recursively using class loader L in order to load and thereby create the component type of C.

  2. The Java Virtual Machine creates a new array class with the indicated component type and number of dimensions.

    If the component type is a reference type, C is marked as having been defined by the defining class loader of the component type. Otherwise, C is marked as having been defined by the bootstrap class loader.

    In any case, the Java Virtual Machine then records that L is an initiating loader for C (5.3.4).

    If the component type is a reference type, the accessibility of the array class is determined by the accessibility of its component type (5.4.4). Otherwise, the array class is accessible to all classes and interfaces.

Deleting this section will necessitate a renumbering or restructuring of the subsequent sections.

Wherever loading constraints are generated (5.4.2, 5.4.3.2, 5.4.3.3), the specification already excludes array types, suggesting that there is no need to track initiating and defining loaders of array types.

Similarly, access checking occurs on the element type of an array type, and need not be repeated for the array type itself (5.4.3.1).

5.3.4 Loading Constraints

Ensuring type safe linkage in the presence of class loaders requires special care. It is possible that when two different class loaders initiate loading of a class or interface denoted by N, the name N may denote a different class or interface in each loader.

When a class or interface C = <N1, L1> makes a symbolic reference to a field or method of another class or interface D = <N2, L2>, the symbolic reference includes a descriptor specifying the type of the field, or the return and argument types of the method. It is essential that any type class or interface name N mentioned in the field or method descriptor (4.3.1, 4.3.2) denote the same class or interface when loaded by L1 and when loaded by L2.

To ensure this, the Java Virtual Machine imposes loading constraints of the form NL1 = NL2 during preparation (5.4.2) and resolution (5.4.3). To enforce these constraints, the Java Virtual Machine will, at certain prescribed times (see 5.3.1, 5.3.2, 5.3.3, and 5.3.5), record that a particular loader is an initiating loader of a particular class. After recording that a loader is an initiating loader of a class, the Java Virtual Machine must immediately check to see if any loading constraints are violated. If so, the record is retracted, the Java Virtual Machine throws a LinkageError, and the loading operation that caused the recording to take place fails.

Similarly, after imposing a loading constraint (see 5.4.2, 5.4.3.2, 5.4.3.3, and 5.4.3.4), the Java Virtual Machine must immediately check to see if any loading constraints are violated. If so, the newly imposed loading constraint is retracted, the Java Virtual Machine throws a LinkageError, and the operation that caused the constraint to be imposed (either resolution or preparation, as the case may be) fails.

The situations described here are the only times at which the Java Virtual Machine checks whether any loading constraints have been violated. A loading constraint is violated if, and only if, all the following four conditions hold:

A full discussion of class loaders and type safety is beyond the scope of this specification. For a more comprehensive discussion, readers are referred to Dynamic Class Loading in the Java Virtual Machine by Sheng Liang and Gilad Bracha (Proceedings of the 1998 ACM SIGPLAN Conference on Object-Oriented Programming Systems, Languages and Applications).

5.3.5 Deriving a Class from a class File Representation

The following steps are used to derive a Class object for the nonarray class or interface C denoted by N using loader L from a purported representation in class file format.

...

5.4 Linking

5.4.2 Preparation

Preparation involves creating the static fields for a class or interface and initializing such fields to their default values (2.3, 2.4). This does not require the execution of any Java Virtual Machine code; explicit initializers for static fields are executed as part of initialization (5.5), not preparation.

During preparation of a class or interface C, the Java Virtual Machine also imposes loading constraints (5.3.4):

  1. Let L1 be the defining loader of C. For each instance method m declared in C that can override (5.4.5) an instance method declared in a superclass or superinterface <D, L2>, the Java Virtual Machine imposes loading constraints as follows for each class or interface name N mentioned by the descriptor of m (4.3.3), the Java Virtual Machine imposes the loading constraint NL1 = NL2.

    Given that the return type of m is Tr, and that the formal parameter types of m are Tf1, ..., Tfn:

    If Tr not an array type, let T0 be Tr; otherwise, let T0 be the element type of Tr.

    For i = 1 to n: If Tfi is not an array type, let Ti be Tfi; otherwise, let Ti be the element type of Tfi.

    Then TiL1 = TiL2 for i = 0 to n.

  2. For each instance method m declared in a superinterface <I, L3> of C, if C does not itself declare an instance method that can override m, then a method is selected (5.4.6) with respect to C and the method m in <I, L3>. Let <D, L2> be the class or interface that declares the selected method. The Java Virtual Machine imposes loading constraints as follows. For each class or interface name N mentioned by the descriptor of m, the Java Virtual Machine imposes the loading constraint NL2 = NL3.

    Given that the return type of m is Tr, and that the formal parameter types of m are Tf1, ..., Tfn:

    If Tr not an array type, let T0 be Tr; otherwise, let T0 be the element type of Tr.

    For i = 1 to n: If Tfi is not an array type, let Ti be Tfi; otherwise, let Ti be the element type of Tfi.

    Then TiL2 = TiL3 for i = 0 to n.

Preparation may occur at any time following creation but must be completed prior to initialization.

5.4.3 Resolution

Many Java Virtual Machine instructions - anewarray, checkcast, getfield, getstatic, instanceof, invokedynamic, invokeinterface, invokespecial, invokestatic, invokevirtual, ldc, ldc_w, ldc2_w, multianewarray, new, putfield, and putstatic - rely on symbolic references in the run-time constant pool. Execution of any of these instructions requires resolution of the symbolic reference.

Resolution is the process of dynamically determining one or more concrete values from a symbolic reference in the run-time constant pool. Initially, all symbolic references in the run-time constant pool are unresolved.

Resolution of an unresolved symbolic reference to (i) a class, or interface, or array type, (ii) a field, (iii) a method, (iv) a method type, (v) a method handle, or (vi) a dynamically-computed constant, proceeds in accordance with the rules given in 5.4.3.1 through 5.4.3.5 5.4.3.6.

...

5.4.3.1 Class, and Interface, and Array Type Resolution

To resolve an unresolved symbolic reference from D to a class or interface C denoted by N, the following steps are performed:

  1. The defining class loader of D is used to create a class or interface denoted by N. This class or interface is C. The details of the process are given in 5.3.

    Any exception that can be thrown as a result of failure of class or interface creation can thus be thrown as a result of failure of class and interface resolution.

  2. If C is an array class and its element type is a reference type, then a symbolic reference to the class or interface representing the element type is resolved by invoking the algorithm in 5.4.3.1 recursively.

  3. Finally, access Access control is applied for the access from D to C (5.4.4).

To resolve an unresolved symbolic reference from D to an array type T, the following steps are performed:

  1. If the element type of the array type is a class or interface type, the named class or interface is resolved, as if by resolution of an unresolved symbolic reference to the named class or interface.

  2. A representation of the array type denoted by the symbolic reference is created.

If steps 1 and 2 succeed but step 3 fails, C is still valid and usable. Nevertheless, resolution fails, and D is prohibited from accessing C. If resolution of a class, interface, or array type successfully loads a class or interface, but a subsequent step (such as access checking) fails, the class or interface is still valid and usable. Nevertheless, resolution fails, and the symbolic reference that was being resolved is invalid.

5.4.3.2 Field Resolution

To resolve an unresolved symbolic reference from D to a field in a class, or interface, or array type C, the symbolic reference to C given by the field reference must first be resolved (5.4.3.1). Therefore, any exception that can be thrown as a result of failure of resolution of a class or interface reference to a class, interface, or array type can be thrown as a result of failure of field resolution. If the reference to C can be successfully resolved, an exception relating to the failure of resolution of the field reference itself can be thrown.

When resolving a field reference, field resolution first attempts to look up the referenced field in C and its superclasses:

  1. If C is a class or interface that declares a field with the name and descriptor specified by the field reference, field lookup succeeds. The declared field is the result of the field lookup.

  2. Otherwise, field lookup is applied recursively to the direct superinterfaces of the specified class or interface C. The direct superinterfaces of an array type are Cloneable and java.io.Serializable (as loaded by the bootstrap class loader).

  3. Otherwise, if C has a direct superclass S, field lookup is applied recursively to S. The direct superclass of an array type is Object.

  4. Otherwise, field lookup fails.

Then, the result of field resolution is determined:

5.4.3.3 Method Resolution

To resolve an unresolved symbolic reference from D to a method in a class or array type C, the symbolic reference to C given by the method reference is first resolved (5.4.3.1). Therefore, any exception that can be thrown as a result of failure of resolution of a class reference to a class, interface, or array type can be thrown as a result of failure of method resolution. If the reference to C can be successfully resolved, exceptions relating to the resolution of the method reference itself can be thrown.

When resolving a method reference:

  1. If C is an interface, method resolution throws an IncompatibleClassChangeError.

  2. Otherwise, method resolution attempts to locate the referenced method in C and its superclasses:

    • If C is a class that declares exactly one method with the name specified by the method reference, and the declaration is a signature polymorphic method (2.9.3), then method lookup succeeds. All the class names mentioned in the descriptor are resolved (5.4.3.1). The descriptor specified by the method reference is resolved, as if by resolution of an unresolved symbolic reference to a method type (5.4.3.5).

      The resolved method is the signature polymorphic method declaration. It is not necessary for C to declare a method with the descriptor specified by the method reference.

    • Otherwise, if C is a class that declares a method with the name and descriptor specified by the method reference, method lookup succeeds.

    • Otherwise, if C is a class and has a superclass, step 2 of method resolution is recursively invoked on the direct superclass of C.

    • Otherwise, if C is an array type and the class Object declares a method with the name and descriptor specified by the method reference, method lookup succeeds.

  3. Otherwise, method resolution attempts to locate the referenced method in the superinterfaces of the specified class C:

    • If the maximally-specific superinterface methods of C for the name and descriptor specified by the method reference include exactly one method that does not have its ACC_ABSTRACT flag set, then this method is chosen and method lookup succeeds.

    • Otherwise, if any superinterface of C declares a method with the name and descriptor specified by the method reference that has neither its ACC_PRIVATE flag nor its ACC_STATIC flag set, one of these is arbitrarily chosen and method lookup succeeds.

    • Otherwise, method lookup fails.

A maximally-specific superinterface method of a class, or interface, or array type C for a particular method name and descriptor is any method for which all of the following are true:

The result of method resolution is determined as follows:

When resolution searches for a method in the a class's superinterfaces, the best outcome is to identify a maximally-specific non-abstract method. It is possible that this method will be chosen by method selection, so it is desirable to add class loader constraints for it.

Otherwise, the result is nondeterministic. This is not new: The Java® Virtual Machine Specification has never identified exactly which method is chosen, and how "ties" should be broken. Prior to Java SE 8, this was mostly an unobservable distinction. However, beginning with Java SE 8, the set of interface methods is more heterogenous, so care must be taken to avoid problems with nondeterministic behavior. Thus:

Note that if the result of resolution is an abstract method, the referenced class C may be non-abstract. Requiring C to be abstract would conflict with the nondeterministic choice of superinterface methods. Instead, resolution assumes that the run time class of the invoked object has a concrete implementation of the method.

5.4.3.4 Interface Method Resolution

To resolve an unresolved symbolic reference from D to an interface method in an interface C, the symbolic reference to C given by the interface method reference is first resolved (5.4.3.1). Therefore, any exception that can be thrown as a result of failure of resolution of an interface reference a reference to a class, interface, or array type can be thrown as a result of failure of interface method resolution. If the reference to C can be successfully resolved, exceptions relating to the resolution of the interface method reference itself can be thrown.

When resolving an interface method reference:

  1. If C is not an interface, interface method resolution throws an IncompatibleClassChangeError.

  2. Otherwise, if C declares a method with the name and descriptor specified by the interface method reference, method lookup succeeds.

  3. Otherwise, if the class Object declares a method with the name and descriptor specified by the interface method reference, which has its ACC_PUBLIC flag set and does not have its ACC_STATIC flag set, method lookup succeeds.

  4. Otherwise, if the maximally-specific superinterface methods (5.4.3.3) of C for the name and descriptor specified by the method reference include exactly one method that does not have its ACC_ABSTRACT flag set, then this method is chosen and method lookup succeeds.

  5. Otherwise, if any superinterface of C declares a method with the name and descriptor specified by the method reference that has neither its ACC_PRIVATE flag nor its ACC_STATIC flag set, one of these is arbitrarily chosen and method lookup succeeds.

  6. Otherwise, method lookup fails.

The result of interface method resolution is determined as follows:

Access control is necessary because interface method resolution may pick a private method of interface C. (Prior to Java SE 8, the result of interface method resolution could be a non-public method of class Object or a static method of class Object; such results were not consistent with the inheritance model of the Java programming language, and are disallowed in Java SE 8 and above.)

5.4.3.5 Method Type and Method Handle Resolution

To resolve an unresolved symbolic reference to a method type, it is as if resolution occurs of unresolved symbolic references to classes and interfaces (5.4.3.1) whose names correspond to the types given in are mentioned by the method descriptor (4.3.3), in the order in which they are mentioned.

Any exception that can be thrown as a result of failure of resolution of a class reference to a class or interface can thus be thrown as a result of failure of method type resolution.

The result of successful method type resolution is a reference to an instance of java.lang.invoke.MethodType which represents the method descriptor.

Method type resolution occurs regardless of whether the run-time constant pool actually contains symbolic references to classes and interfaces indicated in the method descriptor. Also, the resolution is deemed to occur on unresolved symbolic references, so a failure to resolve one method type will not necessarily lead to a later failure to resolve another method type with the same textual method descriptor, if suitable classes and interfaces can be loaded by the later time.

Resolution of an unresolved symbolic reference to a method handle is more complicated. Each method handle resolved by the Java Virtual Machine has an equivalent instruction sequence called its bytecode behavior, indicated by the method handle's kind. The integer values and descriptions of the nine kinds of method handle are given in Table 5.4.3.5-A.

Symbolic references by an instruction sequence to fields or methods are indicated by C.x:T, where x and T are the name and descriptor (4.3.2, 4.3.3) of the field or method, and C is the class, or interface, or array type in which the field or method is to be found.

Table 5.4.3.5-A. Bytecode Behaviors for Method Handles

Kind Description Interpretation
1 REF_getField getfield C.f:T
2 REF_getStatic getstatic C.f:T
3 REF_putField putfield C.f:T
4 REF_putStatic putstatic C.f:T
5 REF_invokeVirtual invokevirtual C.m:(A*)T
6 REF_invokeStatic invokestatic C.m:(A*)T
7 REF_invokeSpecial invokespecial C.m:(A*)T
8 REF_newInvokeSpecial new C; dup; invokespecial C.<init>:(A*)V
9 REF_invokeInterface invokeinterface C.m:(A*)T

Let MH be the symbolic reference to a method handle (5.1) being resolved. Also:

To resolve MH, all symbolic references to classes, interfaces, array types, fields, and methods in MH's bytecode behavior are resolved, using the following four steps:

  1. R is resolved. This occurs as if by field resolution (5.4.3.2) when MH's bytecode behavior is kind 1, 2, 3, or 4, and as if by method resolution (5.4.3.3) when MH's bytecode behavior is kind 5, 6, 7, or 8, and as if by interface method resolution (5.4.3.4) when MH's bytecode behavior is kind 9.

  2. The following constraints apply to the result of resolving R. These constraints correspond to those that would be enforced during verification or execution of the instruction sequence for the relevant bytecode behavior.

    • If MH's bytecode behavior is kind 7 (REF_invokeSpecial), then C must be the current class or interface, a superclass of the current class, a direct superinterface of the current class or interface, or Object.

      Moved this rule here to be clear about the timing and effects of this error check.

    • If MH's bytecode behavior is kind 8 (REF_newInvokeSpecial), then R must resolve to an instance initialization method declared in class C.

    • If R resolves to a protected member, then the following rules apply depending on the kind of MH's bytecode behavior:

      • For kinds 1, 3, and 5 (REF_getField, REF_putField, and REF_invokeVirtual): If C.f or C.m resolved to a protected field or method, and C is a class in in a different run-time package than the current class, then C must be assignable to a subclass of the current class.

        If C is an array type and access checking succeeds, then we're not applying the inheritance clause and this check is not necessary. (See details about protected members of array types in 5.4.4.)

      • For kind 8 (REF_newInvokeSpecial): If C . <init> resolved to a protected method, then C must be declared in the same run-time package as the current class.

    • R must resolve to a static or non-static member depending on the kind of MH's bytecode behavior:

      • For kinds 1, 3, 5, 7, and 9 (REF_getField, REF_putField, REF_invokeVirtual, REF_invokeSpecial, and REF_invokeInterface): C.f or C.m must resolve to a non-static field or method.

      • For kinds 2, 4, and 6 (REF_getStatic, REF_putStatic, and REF_invokeStatic): C.f or C.m must resolve to a static field or method.

  3. Resolution occurs as if of unresolved symbolic references to classes and interfaces whose names correspond to each type in A* , and to the type T, in that order.

    This is phrased incorrectly—not all types correspond to class and interface names. It's also unnecessary: the next step will perform MethodType resolution which, as described above, resolves all the mentioned classes and interfaces.

  4. A reference to an instance of java.lang.invoke.MethodType is obtained as if by resolution of an unresolved symbolic reference to a method type that contains the method descriptor specified in Table 5.4.3.5-B for the kind of MH.

    It is as if the symbolic reference to a method handle contains a symbolic reference to the method type that the resolved method handle will eventually have. The detailed structure of the method type is obtained by inspecting Table 5.4.3.5-B.

    Table 5.4.3.5-B. Method Descriptors for Method Handles

    Kind Description Method descriptor
    1 REF_getField (C)T
    2 REF_getStatic ()T
    3 REF_putField (C,T)V
    4 REF_putStatic (T)V
    5 REF_invokeVirtual (C,A*)T
    6 REF_invokeStatic (A*)T
    7 REF_invokeSpecial (C,A*)T
    8 REF_newInvokeSpecial (A*)C
    9 REF_invokeInterface (C,A*)T

In steps 1, 3, and 4 1 and 3, any exception that can be thrown as a result of failure of resolution of a symbolic reference to a class, interface, field, or method can be thrown as a result of failure of method handle resolution. In step 2, any failure due to the specified constraints causes a failure of method handle resolution due to an IllegalAccessError.

The intent is that resolving a method handle can be done in exactly the same circumstances that the Java Virtual Machine would successfully verify and resolve the symbolic references in the bytecode behavior. In particular, method handles to private, protected, and static members can be created in exactly those classes for which the corresponding normal accesses are legal.

The result of successful method handle resolution is a reference to an instance of java.lang.invoke.MethodHandle which represents the method handle MH.

The type descriptor of this java.lang.invoke.MethodHandle instance is the java.lang.invoke.MethodType instance produced in the third step of method handle resolution above.

The type descriptor of a method handle is such that a valid call to invokeExact in java.lang.invoke.MethodHandle on the method handle has exactly the same stack effects as the bytecode behavior. Calling this method handle on a valid set of arguments has exactly the same effect and returns the same result (if any) as the corresponding bytecode behavior.

If the method referenced by R has the ACC_VARARGS flag set (4.6), then the java.lang.invoke.MethodHandle instance is a variable arity method handle; otherwise, it is a fixed arity method handle.

A variable arity method handle performs argument list boxing (JLS §15.12.4.2) when invoked via invoke, while its behavior with respect to invokeExact is as if the ACC_VARARGS flag were not set.

Method handle resolution throws an IncompatibleClassChangeError if the method referenced by R has the ACC_VARARGS flag set and either A* is an empty sequence or the last parameter type in A* is not an array type. That is, creation of a variable arity method handle fails.

An implementation of the Java Virtual Machine is not required to intern method types or method handles. That is, two distinct symbolic references to method types or method handles which are structurally identical might not resolve to the same instance of java.lang.invoke.MethodType or java.lang.invoke.MethodHandle respectively.

The java.lang.invoke.MethodHandles class in the Java SE Platform API allows creation of method handles with no bytecode behavior. Their behavior is defined by the method of java.lang.invoke.MethodHandles that creates them. For example, a method handle may, when invoked, first apply transformations to its argument values, then supply the transformed values to the invocation of another method handle, then apply a transformation to the value returned from that invocation, then return the transformed value as its own result.

5.4.3.6 Dynamically-Computed Constant and Call Site Resolution

To resolve an unresolved symbolic reference R to a dynamically-computed constant or call site, there are three tasks. First, R is examined to determine which code will serve as its bootstrap method, and which arguments will be passed to that code. Second, the arguments are packaged into an array and the bootstrap method is invoked. Third, the result of the bootstrap method is validated, and used as the result of resolution.

The first task involves the following steps:

  1. R gives a symbolic reference to a bootstrap method handle. The bootstrap method handle is resolved (5.4.3.5) to obtain a reference to an instance of java.lang.invoke.MethodHandle.

    Any exception that can be thrown as a result of failure of resolution of a symbolic reference to a method handle can be thrown in this step.

    If R is a symbolic reference to a dynamically-computed constant, then let D be the type descriptor of the bootstrap method handle. (That is, D is a reference to an instance of java.lang.invoke.MethodType.) The first parameter type indicated by D must be java.lang.invoke.MethodHandles.Lookup, or else resolution fails with a BootstrapMethodError. For historical reasons, the bootstrap method handle for a dynamically-computed call site is not similarly constrained.

  2. If R is a symbolic reference to a dynamically-computed constant, then it gives a field descriptor.

    If the field descriptor indicates a primitive type, then a reference to the pre-defined Class object representing that type is obtained (see the method isPrimitive in class Class).

    Otherwise, the field descriptor indicates a class or interface type, or an array type. A reference to the Class object representing the type indicated by the field descriptor is obtained, as if by resolution of an unresolved symbolic reference to a class, or interface, or array type (5.4.3.1) whose name or descriptor corresponds to the type indicated by the field descriptor.

    Any exception that can be thrown as a result of failure of resolution of a symbolic reference to a class, or interface, or array type can be thrown in this step.

  3. If R is a symbolic reference to a dynamically-computed call site, then it gives a method descriptor.

    A reference to an instance of java.lang.invoke.MethodType is obtained, as if by resolution of an unresolved symbolic reference to a method type (5.4.3.5) with the same parameter and return types as the method descriptor.

    Any exception that can be thrown as a result of failure of resolution of a symbolic reference to a method type can be thrown in this step.

  4. R gives zero or more static arguments, which communicate application-specific metadata to the bootstrap method. Each static argument A is resolved, in the order given by R, as follows:

    • If A is a string constant, then a reference to its instance of class String is obtained.

    • If A is a numeric constant, then a reference to an instance of java.lang.invoke.MethodHandle object representing the number is obtained by the following procedure:

      1. Let v be the value of the numeric constant, and let T be a field descriptor which corresponds to the type of the numeric constant.

      2. Let MH be a method handle produced as if by invocation of the identity method of java.lang.invoke.MethodHandles with an argument representing the class Object.

      3. A reference to an instance of java.lang.invoke.MethodHandle object is obtained as if by the invocation MH.invoke(v) with method descriptor (T)Ljava/lang/Object;.

      This is a bug fix: the value of a static argument representing a number is a boxed number, not a MethodHandle!

    • If A is a symbolic reference to a dynamically-computed constant with a field descriptor indicating a primitive type T, then A is resolved, producing a primitive value v. Given v and T, a reference is obtained to an instance of java.lang.invoke.MethodHandle object encoding v according to the procedure specified above for numeric constants.

    • If A is any other kind of symbolic reference, then the result is the result of resolving A.

    Among the symbolic references in the run-time constant pool, symbolic references to dynamically-computed constants are special because they are derived from constant_pool entries that can syntactically refer to themselves via the BootstrapMethods attribute (4.7.23). However, the Java Virtual Machine does not support resolving a symbolic reference to a dynamically-computed constant that depends on itself (that is, as a static argument to its own bootstrap method). Accordingly, when both R and A are symbolic references to dynamically-computed constants, if A is the same as R or A gives a static argument that (directly or indirectly) references R, then resolution fails with a StackOverflowError at the point where re-resolution of R would be required.

    Unlike class initialization (5.5), where cycles are allowed between uninitialized classes, resolution does not allow cycles in symbolic references to dynamically-computed constants. If an implementation of resolution makes recursive use of a stack, then a StackOverflowError will occur naturally. If not, the implementation is required to detect the cycle rather than, say, looping infinitely or returning a default value for the dynamically-computed constant.

    A similar cycle may arise if the body of a bootstrap method makes reference to a dynamically-computed constant currently being resolved. This has always been possible for invokedynamic bootstraps, and does not require special treatment in resolution; the recursive invokeWithArguments calls will naturally lead to a StackOverflowError.

    Any exception that can be thrown as a result of failure of resolution of a symbolic reference can be thrown in this step.

The second task, to invoke the bootstrap method handle, involves the following steps:

  1. An array is allocated with component type Object and length n+3, where n is the number of static arguments given by R (n 0).

    The zeroth component of the array is set to a reference to an instance of java.lang.invoke.MethodHandles.Lookup for the class in which R occurs, produced as if by invocation of the lookup method of java.lang.invoke.MethodHandles.

    The first component of the array is set to a reference to an instance of String that denotes N, the unqualified name given by R.

    The second component of the array is set to the reference to an instance of Class or java.lang.invoke.MethodType that was obtained earlier for the field descriptor or method descriptor given by R.

    Subsequent components of the array are set to the references that were obtained earlier from resolving R's static arguments, if any. The references appear in the array in the same order as the corresponding static arguments are given by R.

    A Java Virtual Machine implementation may be able to skip allocation of the array and, without any change in observable behavior, pass the arguments directly to the bootstrap method.

  2. The bootstrap method handle is invoked, as if by the invocation BMH.invokeWithArguments(args), where BMH is the bootstrap method handle and args is the array allocated above.

    Due to the behavior of the invokeWithArguments method of java.lang.invoke.MethodHandle, the type descriptor of the bootstrap method handle need not exactly match the run-time types of the arguments. For example, the second parameter type of the bootstrap method handle (corresponding to the unqualified name given in the first component of the array above) could be Object instead of String. If the bootstrap method handle is variable arity, then some or all of the arguments may be collected into a trailing array parameter.

    The invocation occurs within a thread that is attempting resolution of this symbolic reference. If there are several such threads, the bootstrap method handle may be invoked concurrently. Bootstrap methods which access global application data should take the usual precautions against race conditions.

    If the invocation fails by throwing an instance of Error or a subclass of Error, resolution fails with that exception.

    If the invocation fails by throwing an exception that is not an instance of Error or a subclass of Error, resolution fails with a BootstrapMethodError whose cause is the thrown exception.

    If several threads concurrently invoke the bootstrap method handle for this symbolic reference, the Java Virtual Machine chooses the result of one invocation and installs it visibly to all threads. Any other bootstrap methods executing for this symbolic reference are allowed to complete, but their results are ignored.

The third task, to validate the reference, o, produced by invocation of the bootstrap method handle, is as follows:

Many of the steps above perform computations "as if by invocation" of certain methods. In each case, the invocation behavior is given in detail by the specifications for invokestatic and invokevirtual. The invocation occurs in the thread and from the class that is attempting resolution of the symbolic reference R. However, no corresponding method references are required to appear in the run-time constant pool, no particular method's operand stack is necessarily used, and the value of the max_stack item of any method's Code attribute is not enforced for the invocation.

If several threads attempt resolution of R at the same time, the bootstrap method may be invoked concurrently. Therefore, bootstrap methods which access global application data must take precautions against race conditions.

This was stated already, at the end of step 2.

5.4.4 Access Control

Access control is applied during resolution (5.4.3) to ensure that a reference to a class, interface, field, or method is permitted. Access control succeeds if a specified class, interface, field, or method is accessible to the referring class or interface.

A class or interface C is accessible to a class or interface D if and only if one of the following is true:

If C is not accessible to D, access control throws an IllegalAccessError. Otherwise, access control succeeds.

A field or method R is accessible to a class or interface D if and only if any of the following is true:

If R is not accessible to D, then:

Otherwise, access control succeeds.

A nest is a set of classes and interfaces that allow mutual access to their private members. One of the classes or interfaces is the nest host. It enumerates the classes and interfaces which belong to the nest, using the NestMembers attribute (4.7.29). Each of them in turn designates it as the nest host, using the NestHost attribute (4.7.28). A class or interface which lacks a NestHost attribute belongs to the nest hosted by itself; if it also lacks a NestMembers attribute, this nest is a singleton consisting only of the class or interface itself.

To determine whether a class or interface C belongs to the same nest as a class or interface D, the nestmate test is applied. C and D belong to the same nest if and only if the nestmate test succeeds. The nestmate test is as follows:

The nest host of a class or interface M is determined as follows:

5.4.6 Method Selection

During execution of an invokeinterface or invokevirtual instruction, a method is selected with respect to (i) the run-time type of the object on the stack, and (ii) a method that was previously resolved by the instruction. The rules to select a method with respect to a class, or interface, or array type C and a method mR are as follows:

  1. If mR is marked ACC_PRIVATE, then it is the selected method.

  2. Otherwise, the selected method is determined by the following lookup procedure:

    • If C is a class or interface that contains a declaration of an instance method m that can override mR (5.4.5), then m is the selected method.

    • Otherwise, if C is a class and has a superclass, a search for a declaration of an instance method that can override mR is performed, starting with the direct superclass of C and continuing with the direct superclass of that class, and so forth, until a method is found or no further superclasses exist. If a method is found, it is the selected method.

    • Otherwise, if C is an interface or an array type and the class Object declares a method that can override mR, the method declared by Object is the selected method.

    • Otherwise, the maximally-specific superinterface methods of C are determined (5.4.3.3). If exactly one matches mR's name and descriptor and is not abstract, then it is the selected method.

      Any maximally-specific superinterface method selected in this step can override mR; there is no need to check this explicitly.

While C will typically be a class or an array type, it may be an interface when these rules are applied during preparation (5.4.2).

5.5 Initialization

Initialization of a class or interface consists of executing its class or interface initialization method (2.9.2).

A class or interface C may be initialized only as a result of:

Prior to initialization, a class or interface must be linked, that is, verified, prepared, and optionally resolved.

Because the Java Virtual Machine is multithreaded, initialization of a class or interface requires careful synchronization, since some other thread may be trying to initialize the same class or interface at the same time. There is also the possibility that initialization of a class or interface may be requested recursively as part of the initialization of that class or interface. The implementation of the Java Virtual Machine is responsible for taking care of synchronization and recursive initialization by using the following procedure. It assumes that the Class object class or interface has already been verified and prepared, and that the Class object class or interface contains state that indicates one of four situations:

Here and below, we eliminate the unnecessary assertion that the initialization state of the class is stored by an instance of java.lang.Class. The specification need not concern itself with how classes are internally represented and how this representation relates to instances of java.lang.Class.

For each class or interface C, there is a unique initialization lock LC. The mapping from C to LC is left to the discretion of the Java Virtual Machine implementation. For example, LC could be the Class object for C, or the monitor associated with that Class object. The procedure for initializing C is then as follows:

  1. Synchronize on the initialization lock, LC, for C. This involves waiting until the current thread can acquire LC.

  2. If the Class object for C indicates that initialization is in progress for C by some other thread, then release LC and block the current thread until informed that the in-progress initialization has completed, at which time repeat this procedure.

    Thread interrupt status is unaffected by execution of the initialization procedure.

  3. If the Class object for C indicates that initialization is in progress for C by the current thread, then this must be a recursive request for initialization. Release LC and complete normally.

  4. If the Class object for C indicates that C it has already been initialized, then no further action is required. Release LC and complete normally.

  5. If the Class object for C is in an erroneous state, then initialization is not possible. Release LC and throw a NoClassDefFoundError.

  6. Otherwise, record the fact that initialization of the Class object for C is in progress by the current thread, and release LC.

    Then, initialize each final static field of C with the constant value in its ConstantValue attribute (4.7.2), in the order the fields appear in the ClassFile structure.

  7. Next, if C is a class rather than an interface, then let SC be its superclass and let SI1, ..., SIn be all superinterfaces of C (whether direct or indirect) that declare at least one non-abstract, non-static method. The order of superinterfaces is given by a recursive enumeration over the superinterface hierarchy of each interface directly implemented by C. For each interface I directly implemented by C (in the order of the interfaces array of C), the enumeration recurs on I's superinterfaces (in the order of the interfaces array of I) before returning I.

    For each S in the list [ SC, SI1, ..., SIn ], if S has not yet been initialized, then recursively perform this entire procedure for S. If necessary, verify and prepare S first.

    If the initialization of S completes abruptly because of a thrown exception, then acquire LC, label the Class object for C as erroneous, notify all waiting threads, release LC, and complete abruptly, throwing the same exception that resulted from initializing SC S.

  8. Next, determine whether assertions are enabled for C by querying its defining class loader.

  9. Next, if C declares a class or interface initialization method, execute that method.

  10. If the execution of the class or interface initialization method completes normally, then acquire LC, label the Class object for C as fully initialized, notify all waiting threads, release LC, and complete this procedure normally.

  11. Otherwise, the class or interface initialization method must have completed abruptly by throwing some exception E. If the class of E is not Error or one of its subclasses, then create a new instance of the class ExceptionInInitializerError with E as the argument, and use this object in place of E in the following step. If a new instance of ExceptionInInitializerError cannot be created because an OutOfMemoryError occurs, then use an OutOfMemoryError object in place of E in the following step.

  12. Acquire LC, label the Class object for C as erroneous, notify all waiting threads, release LC, and complete this procedure abruptly with reason E or its replacement as determined in the previous step.

A Java Virtual Machine implementation may optimize this procedure by eliding the lock acquisition in step 1 (and release in step 4/5) when it can determine that the initialization of the class has already completed, provided that, in terms of the Java memory model, all happens-before orderings (JLS §17.4.5) that would exist if the lock were acquired, still exist when the optimization is performed.

Chapter 6: The Java Virtual Machine Instruction Set

6.5 Instructions

aastore

Operation

Store into reference array

Format

aastore

Forms

aastore = 83 (0x53)

Operand Stack

..., arrayref, index, value

...

Description

The arrayref must be of type reference and must refer to an array whose components are of type reference. The index must be of type int, and value must be of type reference. The arrayref, index, and value are popped from the operand stack.

If value is null, then value is stored as the component of the array at index.

Otherwise, value is non-null. If the type of value is assignment compatible with the type of the components of the array referenced by arrayref, then value is stored as the component of the array at index. If value is a value of the component type of the array referenced by arrayref, then value is stored as the component of the array at index.

The following rules are used to determine whether a value that is not null is assignment compatible with the array component type. If S is the type of the object referred to by value, and T is the reference type of the array components, then aastore determines whether assignment is compatible as follows:

  • If S is a class type, then:

    • If T is a class type, then S must be the same class as T, or S must be a subclass of T;

    • If T is an interface type, then S must implement interface T.

  • If S is an array type SC[], that is, an array of components of type SC, then:

    • If T is a class type, then T must be Object.

    • If T is an interface type, then T must be one of the interfaces implemented by arrays (JLS §4.10.3).

    • If T is an array type TC[], that is, an array of components of type TC, then one of the following must be true:

      • TC and SC are the same primitive type.

      • TC and SC are reference types, and type SC is assignable to TC by these run-time rules.

Whether value is a value of the array component type is determined according to the rules given for checkcast.

Appealing to "assignment compatible" is a roundabout way to say what we really mean—value must be a value of the array's component type.

aastore, checkcast, and instanceof use the same rules to interpret types. It's helpful to consolidate those rules in one place, so that readers can clearly see that the rules are the same, and so that future enhancements to the type system have fewer rules to maintain.

Run-time Exceptions

If arrayref is null, aastore throws a NullPointerException.

Otherwise, if index is not within the bounds of the array referenced by arrayref, the aastore instruction throws an ArrayIndexOutOfBoundsException.

Otherwise, if arrayref is not null and the actual type of the non-null value is not assignment compatible with the actual type of the components of the array a value of the array component type, aastore throws an ArrayStoreException.

"Otherwise" here implies "arrayref is not null".

anewarray

Operation

Create new array of reference

Format

anewarray
indexbyte1
indexbyte2

Forms

anewarray = 189 (0xbd)

Operand Stack

..., count

..., arrayref

Description

The count must be of type int. It is popped off the operand stack. The count represents the number of components of the array to be created. The unsigned indexbyte1 and indexbyte2 are used to construct an index into the run-time constant pool of the current class (2.6), where the value of the index is (indexbyte1 << 8) | indexbyte2. The run-time constant pool entry at the index must be a symbolic reference to a class, array, or interface type interface, or array type. The named class, array, or interface type interface, or array type is resolved (5.4.3.1). A new array with components of that type component type given by the resolved class, interface, or array type, of length count, is allocated from the garbage-collected heap, and a reference arrayref to this new array object is pushed onto the operand stack. All components of the new array are initialized to null, the default value for reference types (2.4).

Linking Exceptions

During resolution of the symbolic reference to the class, array, or interface type interface, or array type, any of the exceptions documented in 5.4.3.1 can be thrown.

Run-time Exceptions

Otherwise, if count is less than zero, the anewarray instruction throws a NegativeArraySizeException.

Notes

The anewarray instruction is used to create a single dimension of an array of object references or part of a multidimensional array.

checkcast

Operation

Check whether object is of given type

Format

checkcast
indexbyte1
indexbyte2

Forms

checkcast = 192 (0xc0)

Operand Stack

..., objectref

..., objectref

Description

The objectref must be of type reference. The unsigned indexbyte1 and indexbyte2 are used to construct an index into the run-time constant pool of the current class (2.6), where the value of the index is (indexbyte1 << 8) | indexbyte2. The run-time constant pool entry at the index must be a symbolic reference to a class, array, or interface type interface, or array type.

If objectref is null, then the operand stack is unchanged.

Otherwise, the named class, array, or interface type interface, or array type is resolved (5.4.3.1). If objectref can be cast to the resolved class, array, or interface type is a value of the type given by the resolved class, interface, or array type, the operand stack is unchanged; otherwise, the checkcast instruction throws a ClassCastException.

The following rules are used to determine whether an objectref that is not null can be cast to the resolved type a reference to an object is a value of a reference type, T. If S is the type of the object referred to by objectref, and T is the resolved class, array, or interface type, then checkcast determines whether objectref can be cast to type T as follows:

  • If S is a class type the reference is to an instance of a class C, then:

    • If T is a class type, then S must be the same class as T, or S must be a subclass of T;

      If T is the type of a class D, then the reference is a value of T if C is D or a subclass of D.

    • If T is an interface type, then S must implement interface T.

      If T is the type of an interface I, then the reference is a value of T if C implements I.

  • If S is an array type SC[], that is, an array of components of type SC the reference is to an array with component type SC, then:

    • If T is a class type, then T must be Object the reference is a value of T if T is Object.

    • If T is an interface type, then T must be one of the interfaces implemented by arrays (JLS §4.10.3) the reference is a value of T if T is Cloneable or java.io.Serializable (as loaded by the bootstrap class loader).

      It's unnecessary and especially risky to tie JVMS to the Java Language Specification here—we certainly don't want language changes to accidentally impact the routine behavior of JVM instructions.

    • If T is an array type TC[], that is, an array of components of type TC, then one of the following must be true the reference is a value of T if one of the following are true:

      • TC and SC are the same primitive type.

      • TC and SC are reference types, and type SC can be cast to TC by recursive application of these rules.

        Bug fix: an earlier cleanup of these rules (JDK-8069130) removed cases to handle an interface type S. These cases appeared vacuous at the top level, but were necessary to support a recursive analysis for array types. Rather than restoring the old rules, it's probably easier to follow if the recursion is contained within the array type discussion.

        Further, recursion to the top level is no longer a good fit, because the rules are expressed in terms of a specific reference, not types.

      • TC is the class type Object.

      • TC is a class type, SC is a class type, and the class of SC is a subclass of the class of TC.

      • TC is an interface type, SC is a class type, and the class of SC implements the interface of TC.

      • TC is an interface type, SC is an interface type, and the interface of SC extends the interface of TC.

      • TC is the interface type Cloneable or java.io.Serializable (as loaded by the bootstrap class loader), and SC is an array type.

      • TC is an array type TCC[], SC is an array type SCC[], and one of these tests of array component types apply recursively to TCC and SCC.

Linking Exceptions

During resolution of the symbolic reference to the class, array, or interface type interface, or array type, any of the exceptions documented in 5.4.3.1 can be thrown.

Run-time Exception

Otherwise, if objectref cannot be cast to the resolved class, array, or interface type is not null and is not a value of the type given by the resolved class, interface, or array type, the checkcast instruction throws a ClassCastException.

Notes

The checkcast instruction is very similar to the instanceof instruction (6.5.instanceof). It differs in its treatment of null, its behavior when its test fails (checkcast throws an exception, instanceof pushes a result code), and its effect on the operand stack.

getfield

Operation

Fetch field from object

Format

getfield
indexbyte1
indexbyte2

Forms

getfield = 180 (0xb4)

Operand Stack

..., objectref

..., value

Description

The unsigned indexbyte1 and indexbyte2 are used to construct an index into the run-time constant pool of the current class (2.6), where the value of the index is (indexbyte1 << 8) | indexbyte2. The run-time constant pool entry at the index must be a symbolic reference to a field (5.1), which gives the name and descriptor of the field as well as a symbolic reference to the class, interface, or array type in which the field is to be found. The referenced field is resolved (5.4.3.2).

The objectref, which must be of type reference but not an array type, is popped from the operand stack. The value of the referenced field in objectref is fetched and pushed onto the operand stack.

Linking Exceptions

During resolution of the symbolic reference to the field, any of the errors pertaining to field resolution (5.4.3.2) can be thrown.

Otherwise, if the resolved field is a static field, getfield throws an IncompatibleClassChangeError.

Run-time Exception

Otherwise, if objectref is null, the getfield instruction throws a NullPointerException.

Notes

The getfield instruction cannot be used to access the length field length of an array. The arraylength instruction (6.5.arraylength) is used instead.

getstatic

Operation

Get static field from class

Format

getstatic
indexbyte1
indexbyte2

Forms

getstatic = 178 (0xb2)

Operand Stack

...,

..., value

Description

The unsigned indexbyte1 and indexbyte2 are used to construct an index into the run-time constant pool of the current class (2.6), where the value of the index is (indexbyte1 << 8) | indexbyte2. The run-time constant pool entry at the index must be a symbolic reference to a field (5.1), which gives the name and descriptor of the field as well as a symbolic reference to the class, or interface, or array type in which the field is to be found. The referenced field is resolved (5.4.3.2).

On successful resolution of the field, the class or interface that declared the resolved field is initialized if that class or interface has not already been initialized (5.5).

The value of the class or interface field is fetched and pushed onto the operand stack.

Linking Exceptions

During resolution of the symbolic reference to the class or interface field, any of the exceptions pertaining to field resolution (5.4.3.2) can be thrown.

Otherwise, if the resolved field is not a static (class) field or an interface field, getstatic throws an IncompatibleClassChangeError.

Run-time Exception

Otherwise, if execution of this getstatic instruction causes initialization of the referenced declaring class or interface, getstatic may throw an Error as detailed in 5.5.

instanceof

Operation

Determine if object is of given type

Format

instanceof
indexbyte1
indexbyte2

Forms

instanceof = 193 (0xc1)

Operand Stack

..., objectref

..., result

Description

The objectref, which must be of type reference, is popped from the operand stack. The unsigned indexbyte1 and indexbyte2 are used to construct an index into the run-time constant pool of the current class (2.6), where the value of the index is (indexbyte1 << 8) | indexbyte2. The run-time constant pool entry at the index must be a symbolic reference to a class, array, or interface type interface, or array type.

If objectref is null, the instanceof instruction pushes an int result of 0 as an int onto the operand stack.

Otherwise, the named class, array, or interface type interface, or array type is resolved (5.4.3.1). If objectref is an instance of a value of the type given by the resolved class, interface, or array type, or implements the resolved interface, the instanceof instruction pushes an int result of 1 as an int onto the operand stack; otherwise, it pushes an int result of 0.

The following rules are used to determine whether an objectref that is not null is an instance of the resolved type. If S is the type of the object referred to by objectref, and T is the resolved class, array, or interface type, then instanceof determines whether objectref is an instance of T as follows:

  • If S is a class type, then:

    • If T is a class type, then S must be the same class as T, or S must be a subclass of T;

    • If T is an interface type, then S must implement interface T.

  • If S is an array type SC[], that is, an array of components of type SC, then:

    • If T is a class type, then T must be Object.

    • If T is an interface type, then T must be one of the interfaces implemented by arrays (JLS §4.10.3).

    • If T is an array type TC[], that is, an array of components of type TC, then one of the following must be true:

      • TC and SC are the same primitive type.

      • TC and SC are reference types, and type SC can be cast to TC by these run-time rules.

Whether objectref is a value of the type given by the resolved class, interface, or array type is determined according to the rules given for checkcast.

aastore, checkcast, and instanceof use the same rules to interpret types. It's helpful to consolidate those rules in one place, so that readers can clearly see that the rules are the same, and so that future enhancements to the type system have fewer rules to maintain.

Linking Exceptions

During resolution of the symbolic reference to the class, array, or interface type interface, or array type, any of the exceptions documented in 5.4.3.1 can be thrown.

Notes

The instanceof instruction is very similar to the checkcast instruction (6.5.checkcast). It differs in its treatment of null, its behavior when its test fails (checkcast throws an exception, instanceof pushes a result code), and its effect on the operand stack.

invokeinterface

Operation

Invoke interface method

Format

invokeinterface
indexbyte1
indexbyte2
count
0

Forms

invokeinterface = 185 (0xb9)

Operand Stack

..., objectref, [arg1, [arg2 ...]]

...

Description

The unsigned indexbyte1 and indexbyte2 are used to construct an index into the run-time constant pool of the current class (2.6), where the value of the index is (indexbyte1 << 8) | indexbyte2. The run-time constant pool entry at the index must be a symbolic reference to an interface method (5.1), which gives the name and descriptor (4.3.3) of the interface method as well as a symbolic reference to the class, interface, or array type in which the interface method is to be found. The named interface method is resolved (5.4.3.4).

The resolved interface method must not be an instance initialization method, or the a class or interface initialization method (2.9.1, 2.9.2).

The count operand is an unsigned byte that must not be zero. The objectref must be of type reference and must be followed on the operand stack by nargs argument values, where the number, type, and order of the values must be consistent with the descriptor of the resolved interface method. The value of the fourth operand byte must always be zero.

Let C be the class or array type of objectref. A method is selected with respect to C and the resolved method (5.4.6). This is the method to be invoked.

If the method to be invoked is synchronized, the monitor associated with objectref is entered or reentered as if by execution of a monitorenter instruction (6.5.monitorenter) in the current thread.

If the method to be invoked is not native, the nargs argument values and objectref are popped from the operand stack. A new frame is created on the Java Virtual Machine stack for the method being invoked. The objectref and the argument values are consecutively made the values of local variables of the new frame, with objectref in local variable 0, arg1 in local variable 1 (or, if arg1 is of type long or double, in local variables 1 and 2), and so on. Any argument value that is of a floating-point type undergoes value set conversion (2.8.3) prior to being stored in a local variable. The new frame is then made current, and the Java Virtual Machine pc is set to the opcode of the first instruction of the method to be invoked. Execution continues with the first instruction of the method.

If the method to be invoked is native and the platform-dependent code that implements it has not yet been bound (5.6) into the Java Virtual Machine, then that is done. The nargs argument values and objectref are popped from the operand stack and are passed as parameters to the code that implements the method. Any argument value that is of a floating-point type undergoes value set conversion (2.8.3) prior to being passed as a parameter. The parameters are passed and the code is invoked in an implementation-dependent manner. When the platform-dependent code returns:

  • If the native method is synchronized, the monitor associated with objectref is updated and possibly exited as if by execution of a monitorexit instruction (6.5.monitorexit) in the current thread.

  • If the native method returns a value, the return value of the platform-dependent code is converted in an implementation-dependent way to the return type of the native method and pushed onto the operand stack.

Linking Exceptions

During resolution of the symbolic reference to the interface method, any of the exceptions pertaining to interface method resolution (5.4.3.4) can be thrown.

Otherwise, if the resolved method is static, the invokeinterface instruction throws an IncompatibleClassChangeError.

Note that invokeinterface may refer to private methods declared in interfaces, including nestmate interfaces.

Run-time Exceptions

Otherwise, if objectref is null, the invokeinterface instruction throws a NullPointerException.

Otherwise, if the class or array type of objectref does not implement the resolved interface, invokeinterface throws an IncompatibleClassChangeError.

Otherwise, if the selected method is neither public nor private, invokeinterface throws an IllegalAccessError.

Otherwise, if the selected method is abstract, invokeinterface throws an AbstractMethodError.

Otherwise, if the selected method is native and the code that implements the method cannot be bound, invokeinterface throws an UnsatisfiedLinkError.

Otherwise, if no method is selected, and there are multiple maximally-specific superinterface methods of C that match the resolved method's name and descriptor and are not abstract, invokeinterface throws an IncompatibleClassChangeError.

Otherwise, if no method is selected, and there are no maximally-specific superinterface methods of C that match the resolved method's name and descriptor and are not abstract, invokeinterface throws an AbstractMethodError.

Notes

The count operand of the invokeinterface instruction records a measure of the number of argument values, where an argument value of type long or type double contributes two units to the count value and an argument of any other type contributes one unit. This information can also be derived from the descriptor of the selected method. The redundancy is historical.

The fourth operand byte exists to reserve space for an additional operand used in certain of Oracle's Java Virtual Machine implementations, which replace the invokeinterface instruction by a specialized pseudo-instruction at run time. It must be retained for backwards compatibility.

The nargs argument values and objectref are not one-to-one with the first nargs+1 local variables. Argument values of types long and double must be stored in two consecutive local variables, thus more than nargs local variables may be required to pass nargs argument values to the invoked method.

The selection logic allows a non-abstract method declared in a superinterface to be selected. Methods in interfaces are only considered if there is no matching method in the class hierarchy. In the event that there are two non-abstract methods in the superinterface hierarchy, with neither more specific than the other, an error occurs; there is no attempt to disambiguate (for example, one may be the referenced method and one may be unrelated, but we do not prefer the referenced method). On the other hand, if there are many abstract methods but only one non-abstract method, the non-abstract method is selected (unless an abstract method is more specific).

invokespecial

Operation

Invoke instance method; direct invocation of instance initialization methods and methods of the current class and its supertypes

Format

invokespecial
indexbyte1
indexbyte2

Forms

invokespecial = 183 (0xb7)

Operand Stack

..., objectref, [arg1, [arg2 ...]]

...

Description

The unsigned indexbyte1 and indexbyte2 are used to construct an index into the run-time constant pool of the current class (2.6), where the value of the index is (indexbyte1 << 8) | indexbyte2. The run-time constant pool entry at the index must be a symbolic reference to a method or an interface method (5.1), which gives the name and descriptor (4.3.3) of the method or interface method as well as a symbolic reference to the class, or interface, or array type in which the method or interface method is to be found. The named method is resolved (5.4.3.3, 5.4.3.4).

The symbolic reference must reference a class or interface.

If the symbolic reference names a class (not an interface), and the resolved method is not an instance initialization method (2.9.1), let C be the direct superclass of the current class.
Otherwise, let C be the class or interface named by the symbolic reference.

The actual method to be invoked is selected by the following lookup procedure:

  1. If C contains a declaration for an instance method with the same name and descriptor as the resolved method, then it is the method to be invoked.

  2. Otherwise, if C is a class and has a superclass, a search for a declaration of an instance method with the same name and descriptor as the resolved method is performed, starting with the direct superclass of C and continuing with the direct superclass of that class, and so forth, until a match is found or no further superclasses exist. If a match is found, then it is the method to be invoked.

  3. Otherwise, if C is an interface and the class Object contains a declaration of a public instance method with the same name and descriptor as the resolved method, then it is the method to be invoked.

  4. Otherwise, if there is exactly one maximally-specific method (5.4.3.3) in the superinterfaces of C that matches the resolved method's name and descriptor and is not abstract, then it is the method to be invoked.

The objectref must be of type reference and must be followed on the operand stack by nargs argument values, where the number, type, and order of the values must be consistent with the descriptor of the selected instance method.

If the method is synchronized, the monitor associated with objectref is entered or reentered as if by execution of a monitorenter instruction (6.5.monitorenter) in the current thread.

If the method is not native, the nargs argument values and objectref are popped from the operand stack. A new frame is created on the Java Virtual Machine stack for the method being invoked. The objectref and the argument values are consecutively made the values of local variables of the new frame, with objectref in local variable 0, arg1 in local variable 1 (or, if arg1 is of type long or double, in local variables 1 and 2), and so on. Any argument value that is of a floating-point type undergoes value set conversion (2.8.3) prior to being stored in a local variable. The new frame is then made current, and the Java Virtual Machine pc is set to the opcode of the first instruction of the method to be invoked. Execution continues with the first instruction of the method.

If the method is native and the platform-dependent code that implements it has not yet been bound (5.6) into the Java Virtual Machine, that is done. The nargs argument values and objectref are popped from the operand stack and are passed as parameters to the code that implements the method. Any argument value that is of a floating-point type undergoes value set conversion (2.8.3) prior to being passed as a parameter. The parameters are passed and the code is invoked in an implementation-dependent manner. When the platform-dependent code returns, the following take place:

  • If the native method is synchronized, the monitor associated with objectref is updated and possibly exited as if by execution of a monitorexit instruction (6.5.monitorexit) in the current thread.

  • If the native method returns a value, the return value of the platform-dependent code is converted in an implementation-dependent way to the return type of the native method and pushed onto the operand stack.

Linking Exceptions

During resolution of the symbolic reference to the method, any of the exceptions pertaining to method resolution (5.4.3.3) can be thrown.

Otherwise, if the resolved method is an instance initialization method, and the class in which it is declared is not the class, interface, or array type symbolically referenced by the instruction, a NoSuchMethodError is thrown.

Otherwise, if the resolved method is a class (static) method, the invokespecial instruction throws an IncompatibleClassChangeError.

Run-time Exceptions

Otherwise, if objectref is null, the invokespecial instruction throws a NullPointerException.

Otherwise, if step 1, step 2, or step 3 of the lookup procedure selects an abstract method, invokespecial throws an AbstractMethodError.

Otherwise, if step 1, step 2, or step 3 of the lookup procedure selects a native method and the code that implements the method cannot be bound, invokespecial throws an UnsatisfiedLinkError.

Otherwise, if step 4 of the lookup procedure determines there are multiple maximally-specific superinterface methods of C that match the resolved method's name and descriptor and are not abstract, invokespecial throws an IncompatibleClassChangeError

Otherwise, if step 4 of the lookup procedure determines there are no maximally-specific superinterface methods of C that match the resolved method's name and descriptor and are not abstract, invokespecial throws an AbstractMethodError.

Notes

The difference between the invokespecial instruction and the invokevirtual instruction (6.5.invokevirtual) is that invokevirtual invokes a method based on the class of the object. The invokespecial instruction is used to directly invoke instance initialization methods (2.9.1) as well as methods of the current class and its supertypes.

The invokespecial instruction was named invokenonvirtual prior to JDK release 1.0.2.

The nargs argument values and objectref are not one-to-one with the first nargs+1 local variables. Argument values of types long and double must be stored in two consecutive local variables, thus more than nargs local variables may be required to pass nargs argument values to the invoked method.

The invokespecial instruction handles invocation of a non-abstract interface method, referenced either via a direct superinterface or via a superclass. In these cases, the rules for selection are essentially the same as those for invokeinterface (except that the search starts from a different class).

invokestatic

Operation

Invoke a class (static) method

Format

invokestatic
indexbyte1
indexbyte2

Forms

invokestatic = 184 (0xb8)

Operand Stack

..., [arg1, [arg2 ...]]

...

Description

The unsigned indexbyte1 and indexbyte2 are used to construct an index into the run-time constant pool of the current class (2.6), where the value of the index is (indexbyte1 << 8) | indexbyte2. The run-time constant pool entry at the index must be a symbolic reference to a method or an interface method (5.1), which gives the name and descriptor (4.3.3) of the method or interface method as well as a symbolic reference to the class, or interface, or array type in which the method or interface method is to be found. The named method is resolved (5.4.3.3, 5.4.3.4).

The resolved method must not be an instance initialization method, or the a class or interface initialization method (2.9.1, 2.9.2).

The resolved method must be static, and therefore cannot be abstract.

On successful resolution of the method, the class or interface that declared the resolved method is initialized if that class or interface has not already been initialized (5.5).

The operand stack must contain nargs argument values, where the number, type, and order of the values must be consistent with the descriptor of the resolved method.

If the method is synchronized, the monitor associated with the resolved Class object is entered or reentered as if by execution of a monitorenter instruction (6.5.monitorenter) in the current thread.

If the method is not native, the nargs argument values are popped from the operand stack. A new frame is created on the Java Virtual Machine stack for the method being invoked. The nargs argument values are consecutively made the values of local variables of the new frame, with arg1 in local variable 0 (or, if arg1 is of type long or double, in local variables 0 and 1) and so on. Any argument value that is of a floating-point type undergoes value set conversion (2.8.3) prior to being stored in a local variable. The new frame is then made current, and the Java Virtual Machine pc is set to the opcode of the first instruction of the method to be invoked. Execution continues with the first instruction of the method.

If the method is native and the platform-dependent code that implements it has not yet been bound (5.6) into the Java Virtual Machine, that is done. The nargs argument values are popped from the operand stack and are passed as parameters to the code that implements the method. Any argument value that is of a floating-point type undergoes value set conversion (2.8.3) prior to being passed as a parameter. The parameters are passed and the code is invoked in an implementation-dependent manner. When the platform-dependent code returns, the following take place:

  • If the native method is synchronized, the monitor associated with the resolved Class object is updated and possibly exited as if by execution of a monitorexit instruction (6.5.monitorexit) in the current thread.

  • If the native method returns a value, the return value of the platform-dependent code is converted in an implementation-dependent way to the return type of the native method and pushed onto the operand stack.

Linking Exceptions

During resolution of the symbolic reference to the method, any of the exceptions pertaining to method resolution (5.4.3.3) can be thrown.

Otherwise, if the resolved method is an instance method, the invokestatic instruction throws an IncompatibleClassChangeError.

Run-time Exceptions

Otherwise, if execution of this invokestatic instruction causes initialization of the referenced declaring class or interface, invokestatic may throw an Error as detailed in 5.5.

Otherwise, if the resolved method is native and the code that implements the method cannot be bound, invokestatic throws an UnsatisfiedLinkError.

Notes

The nargs argument values are not one-to-one with the first nargs local variables. Argument values of types long and double must be stored in two consecutive local variables, thus more than nargs local variables may be required to pass nargs argument values to the invoked method.

invokevirtual

Operation

Invoke instance method; dispatch based on class

Format

invokevirtual
indexbyte1
indexbyte2

Forms

invokevirtual = 182 (0xb6)

Operand Stack

..., objectref, [arg1, [arg2 ...]]

...

Description

The unsigned indexbyte1 and indexbyte2 are used to construct an index into the run-time constant pool of the current class (2.6), where the value of the index is (indexbyte1 << 8) | indexbyte2. The run-time constant pool entry at the index must be a symbolic reference to a method (5.1), which gives the name and descriptor (4.3.3) of the method as well as a symbolic reference to the class, interface, or array type in which the method is to be found. The named method is resolved (5.4.3.3).

If the resolved method is not signature polymorphic (2.9.3), then the invokevirtual instruction proceeds as follows.

Let C be the class or array type of objectref. A method is selected with respect to C and the resolved method (5.4.6). This is the method to be invoked.

The objectref must be followed on the operand stack by nargs argument values, where the number, type, and order of the values must be consistent with the descriptor of the selected instance method.

If the method to be invoked is synchronized, the monitor associated with objectref is entered or reentered as if by execution of a monitorenter instruction (6.5.monitorenter) in the current thread.

If the method to be invoked is not native, the nargs argument values and objectref are popped from the operand stack. A new frame is created on the Java Virtual Machine stack for the method being invoked. The objectref and the argument values are consecutively made the values of local variables of the new frame, with objectref in local variable 0, arg1 in local variable 1 (or, if arg1 is of type long or double, in local variables 1 and 2), and so on. Any argument value that is of a floating-point type undergoes value set conversion (2.8.3) prior to being stored in a local variable. The new frame is then made current, and the Java Virtual Machine pc is set to the opcode of the first instruction of the method to be invoked. Execution continues with the first instruction of the method.

If the method to be invoked is native and the platform-dependent code that implements it has not yet been bound (5.6) into the Java Virtual Machine, that is done. The nargs argument values and objectref are popped from the operand stack and are passed as parameters to the code that implements the method. Any argument value that is of a floating-point type undergoes value set conversion (2.8.3) prior to being passed as a parameter. The parameters are passed and the code is invoked in an implementation-dependent manner. When the platform-dependent code returns, the following take place:

  • If the native method is synchronized, the monitor associated with objectref is updated and possibly exited as if by execution of a monitorexit instruction (6.5.monitorexit) in the current thread.

  • If the native method returns a value, the return value of the platform-dependent code is converted in an implementation-dependent way to the return type of the native method and pushed onto the operand stack.

If the resolved method is signature polymorphic (2.9.3), and declared in the java.lang.invoke.MethodHandle class, then the invokevirtual instruction proceeds as follows, where D is the descriptor of the method symbolically referenced by the instruction.

First, a reference to an instance of java.lang.invoke.MethodType is obtained as if by resolution of a symbolic reference to a method type (5.4.3.5) with the same parameter and return types as D.

  • If the named method is invokeExact, the instance of java.lang.invoke.MethodType must be semantically equal to the type descriptor of the receiving method handle objectref. The method handle to be invoked is objectref.

  • If the named method is invoke, and the instance of java.lang.invoke.MethodType is semantically equal to the type descriptor of the receiving method handle objectref, then the method handle to be invoked is objectref.

  • If the named method is invoke, and the instance of java.lang.invoke.MethodType is not semantically equal to the type descriptor of the receiving method handle objectref, then the Java Virtual Machine attempts to adjust the type descriptor of the receiving method handle, as if by invocation of the asType method of java.lang.invoke.MethodHandle, to obtain an exactly invokable method handle m. The method handle to be invoked is m.

The objectref must be followed on the operand stack by nargs argument values, where the number, type, and order of the values must be consistent with the type descriptor of the method handle to be invoked. (This type descriptor will correspond to the method descriptor appropriate for the kind of the method handle to be invoked, as specified in 5.4.3.5.)

Then, if the method handle to be invoked has bytecode behavior, the Java Virtual Machine invokes the method handle as if by execution of the bytecode behavior associated with the method handle's kind. If the kind is 5 (REF_invokeVirtual), 6 (REF_invokeStatic), 7 (REF_invokeSpecial), 8 (REF_newInvokeSpecial), or 9 (REF_invokeInterface), then a frame will be created and made current in the course of executing the bytecode behavior; however, this frame is not visible, and when the method invoked by the bytecode behavior completes (normally or abruptly), the frame of its invoker is considered to be the frame for the method containing this invokevirtual instruction.

Otherwise, if the method handle to be invoked has no bytecode behavior, the Java Virtual Machine invokes it in an implementation-dependent manner.

If the resolved method is signature polymorphic and declared in the java.lang.invoke.VarHandle class, then the invokevirtual instruction proceeds as follows, where N and D are the name and descriptor of the method symbolically referenced by the instruction.

First, a reference to an instance of java.lang.invoke.VarHandle.AccessMode is obtained as if by invocation of the valueFromMethodName method of java.lang.invoke.VarHandle.AccessMode with a String argument denoting N.

Second, a reference to an instance of java.lang.invoke.MethodType is obtained as if by invocation of the accessModeType method of java.lang.invoke.VarHandle on the instance objectref, with the instance of java.lang.invoke.VarHandle.AccessMode as the argument.

Third, a reference to an instance of java.lang.invoke.MethodHandle is obtained as if by invocation of the varHandleExactInvoker method of java.lang.invoke.MethodHandles with the instance of java.lang.invoke.VarHandle.AccessMode as the first argument and the instance of java.lang.invoke.MethodType as the second argument. The resulting instance is called the invoker method handle.

Finally, the nargs argument values and objectref are popped from the operand stack, and the invoker method handle is invoked. The invocation occurs as if by execution of an invokevirtual instruction that indicates a run-time constant pool index to a symbolic reference R where:

  • R is a symbolic reference to a method of a class;

  • for the symbolic reference to the class in which the method is to be found, R specifies java.lang.invoke.MethodHandle;

  • for the name of the method, R specifies invoke;

  • for the descriptor of the method, R specifies a return type indicated by the return descriptor of D, and specifies a first parameter type of java.lang.invoke.VarHandle followed by the parameter types indicated by the parameter descriptors of D (if any) in order.

and where it is as if the following items were pushed, in order, onto the operand stack:

  • a reference to the instance of java.lang.invoke.MethodHandle (the invoker method handle);

  • objectref;

  • the nargs argument values, where the number, type, and order of the values must be consistent with the type descriptor of the invoker method handle.

Linking Exceptions

During resolution of the symbolic reference to the method, any of the exceptions pertaining to method resolution (5.4.3.3) can be thrown.

Otherwise, if the resolved method is a class (static) method, the invokevirtual instruction throws an IncompatibleClassChangeError.

Otherwise, if the resolved method is signature polymorphic and declared in the java.lang.invoke.MethodHandle class, then during resolution of the method type derived from the descriptor in the symbolic reference to the method, any of the exceptions pertaining to method type resolution (5.4.3.5) can be thrown.

Otherwise, if the resolved method is signature polymorphic and declared in the java.lang.invoke.VarHandle class, then any linking exception that may arise from invocation of the invoker method handle can be thrown. No linking exceptions are thrown from invocation of the valueFromMethodName, accessModeType, and varHandleExactInvoker methods.

Run-time Exceptions

Otherwise, if objectref is null, the invokevirtual instruction throws a NullPointerException.

Otherwise, if the resolved method is not signature polymorphic:

  • If the selected method is abstract, invokevirtual throws an AbstractMethodError.

  • Otherwise, if the selected method is native and the code that implements the method cannot be bound, invokevirtual throws an UnsatisfiedLinkError.

  • Otherwise, if no method is selected, and there are multiple maximally-specific superinterface methods of C that match the resolved method's name and descriptor and are not abstract, invokevirtual throws an IncompatibleClassChangeError.

  • Otherwise, if no method is selected, and there are no maximally-specific superinterface methods of C that match the resolved method's name and descriptor and are not abstract, invokevirtual throws an AbstractMethodError.

Otherwise, if the resolved method is signature polymorphic and declared in the java.lang.invoke.MethodHandle class, then:

  • If the method name is invokeExact, and the obtained instance of java.lang.invoke.MethodType is not semantically equal to the type descriptor of the receiving method handle objectref, the invokevirtual instruction throws a java.lang.invoke.WrongMethodTypeException.

  • If the method name is invoke, and the obtained instance of java.lang.invoke.MethodType is not a valid argument to the asType method of java.lang.invoke.MethodHandle invoked on the receiving method handle objectref, the invokevirtual instruction throws a java.lang.invoke.WrongMethodTypeException.

Otherwise, if the resolved method is signature polymorphic and declared in the java.lang.invoke.VarHandle class, then any run-time exception that may arise from invocation of the invoker method handle can be thrown. No run-time exceptions are thrown from invocation of the valueFromMethodName, accessModeType, and varHandleExactInvoker methods, except NullPointerException if objectref is null.

Notes

The nargs argument values and objectref are not one-to-one with the first nargs+1 local variables. Argument values of types long and double must be stored in two consecutive local variables, thus more than nargs local variables may be required to pass nargs argument values to the invoked method.

It is possible that the symbolic reference of an invokevirtual instruction resolves to an interface method. In this case, it is possible that there is no overriding method in the class hierarchy, but that a non-abstract interface method matches the resolved method's descriptor. The selection logic matches such a method, using the same rules as for invokeinterface.

ldc

Operation

Push item from run-time constant pool

Format

ldc
index

Forms

ldc = 18 (0x12)

Operand Stack

...

..., value

Description

The index is an unsigned byte that must be a valid index into the run-time constant pool of the current class (2.5.5). The run-time constant pool entry at index must be loadable (5.1), and not any of the following:

  • A numeric constant of type long or double.

  • A symbolic reference to a dynamically-computed constant whose field descriptor is J (denoting long) or D (denoting double).

If the run-time constant pool entry is a numeric constant of type int or float, then the value of that numeric constant is pushed onto the operand stack as an int or float, respectively.

Otherwise, if the run-time constant pool entry is a string constant, that is, a reference to an instance of class String, then value, a reference to that instance, is pushed onto the operand stack.

Otherwise, if the run-time constant pool entry is a symbolic reference to a class, or interface, or array type, then the named class or interface symbolic reference is resolved (5.4.3.1) and value, a reference to the Class object representing that class, or interface, or array type, is pushed onto the operand stack.

Otherwise, the run-time constant pool entry is a symbolic reference to a method type, a method handle, or a dynamically-computed constant. The symbolic reference is resolved (5.4.3.5, 5.4.3.6) and value, the result of resolution, is pushed onto the operand stack.

Linking Exceptions

During resolution of a symbolic reference, any of the exceptions pertaining to resolution of that kind of symbolic reference can be thrown.

Notes

The ldc instruction can only be used to push a value of type float taken from the float value set (2.3.2) because a constant of type float in the constant pool (4.4.4) must be taken from the float value set.

ldc_w

Operation

Push item from run-time constant pool (wide index)

Format

ldc_w
indexbyte1
indexbyte2

Forms

ldc_w = 19 (0x13)

Operand Stack

...

..., value

Description

The unsigned indexbyte1 and indexbyte2 are assembled into an unsigned 16-bit index into the run-time constant pool of the current class (2.5.5), where the value of the index is calculated as (indexbyte1 << 8) | indexbyte2. The index must be a valid index into the run-time constant pool of the current class. The run-time constant pool entry at the index must be loadable (5.1), and not any of the following:

  • A numeric constant of type long or double.

  • A symbolic reference to a dynamically-computed constant whose field descriptor is J (denoting long) or D (denoting double).

If the run-time constant pool entry is a numeric constant of type int or float, or a string constant, then value is determined and pushed onto the operand stack according to the rules given for the ldc instruction.

Otherwise, the run-time constant pool entry is a symbolic reference to a class, interface, array type, method type, method handle, or dynamically-computed constant. It is resolved and value is determined and pushed onto the operand stack according to the rules given for the ldc instruction.

Linking Exceptions

During resolution of a symbolic reference, any of the exceptions pertaining to resolution of that kind of symbolic reference can be thrown.

Notes

The ldc_w instruction is identical to the ldc instruction (6.5.ldc) except for its wider run-time constant pool index.

The ldc_w instruction can only be used to push a value of type float taken from the float value set (2.3.2) because a constant of type float in the constant pool (4.4.4) must be taken from the float value set.

multianewarray

Operation

Create new multidimensional array

Format

multianewarray
indexbyte1
indexbyte2
dimensions

Forms

multianewarray = 197 (0xc5)

Operand Stack

..., count1, [count2, ...]

..., arrayref

Description

The dimensions operand is an unsigned byte that must be greater than or equal to 1. It represents the number of dimensions of the array to be created. The operand stack must contain dimensions values. Each such value represents the number of components in a dimension of the array to be created, must be of type int, and must be non-negative. The count1 is the desired length in the first dimension, count2 in the second, etc.

All of the count values are popped off the operand stack. The unsigned indexbyte1 and indexbyte2 are used to construct an index into the run-time constant pool of the current class (2.6), where the value of the index is (indexbyte1 << 8) | indexbyte2. The run-time constant pool entry at the index must be a symbolic reference to a class, array, or interface type an array type. The named class, array, or interface type referenced array type is resolved (5.4.3.1). The resulting entry must be an array class type of dimensionality greater than or equal to dimensions.

Verification has ensured that the referenced CONSTANT_Class_info denotes an array type.

A new multidimensional array of the array type is allocated from the garbage-collected heap. If any count value is zero, no subsequent dimensions are allocated. The components of the array in the first dimension are initialized to subarrays of the type of the second dimension, and so on. The components of the last allocated dimension of the array are initialized to the default initial value (2.3, 2.4) for the element type of the array type component type of that dimension. A reference arrayref to the new array is pushed onto the operand stack.

Linking Exceptions

During resolution of the symbolic reference to the class, array, or interface type array type, any of the exceptions documented in 5.4.3.1 can be thrown.

Otherwise, if the current class does not have permission to access the element type of the resolved array class, multianewarray throws an IllegalAccessError.

If the element type is inaccessible, resolution will fail.

Run-time Exception

Otherwise, if any of the dimensions values on the operand stack are less than zero, the multianewarray instruction throws a NegativeArraySizeException.

Notes

It may be more efficient to use newarray or anewarray (6.5.newarray, 6.5.anewarray) when creating an array of a single dimension.

The array class type referenced via the run-time constant pool may have more dimensions than the dimensions operand of the multianewarray instruction. In that case, only the first dimensions of the dimensions of the array are created.

new

Operation

Create new object

Format

new
indexbyte1
indexbyte2

Forms

new = 187 (0xbb)

Operand Stack

...

..., objectref

Description

The unsigned indexbyte1 and indexbyte2 are used to construct an index into the run-time constant pool of the current class (2.6), where the value of the index is (indexbyte1 << 8) | indexbyte2. The run-time constant pool entry at the index must be a symbolic reference to a class or interface type. The named class or interface type is resolved (5.4.3.1) and should result in a non-abstract class type. Memory for a new instance of that class is allocated from the garbage-collected heap, and the instance variables of the new object are initialized to their the default initial values of their types (2.3, 2.4). The objectref, a reference to the instance, is pushed onto the operand stack.

On successful resolution of the class, it is initialized if it has not already been initialized (5.5).

Linking Exceptions

During resolution of the symbolic reference to the class or interface type, any of the exceptions documented in 5.4.3.1 can be thrown.

Otherwise, if the symbolic reference to the class or interface type resolves to an interface or an abstract class, new throws an InstantiationError.

Run-time Exception

Otherwise, if execution of this new instruction causes initialization of the referenced class, new may throw an Error as detailed in JLS §15.9.4 5.5.

This is an unnecessary JLS reference, and also appears to be out of date: JLS 15.9.4 doesn't describe class initialization at all.

Notes

The new instruction does not completely create a new instance; instance creation is not completed until an instance initialization method (2.9.1) has been invoked on the uninitialized instance.

putfield

Operation

Set field in object

Format

putfield
indexbyte1
indexbyte2

Forms

putfield = 181 (0xb5)

Operand Stack

..., objectref, value

...

Description

The unsigned indexbyte1 and indexbyte2 are used to construct an index into the run-time constant pool of the current class (2.6), where the value of the index is (indexbyte1 << 8) | indexbyte2. The run-time constant pool entry at the index must be a symbolic reference to a field (5.1), which gives the name and descriptor of the field as well as a symbolic reference to the class, interface, or array type in which The referenced field is resolved (5.4.3.2).

The type of a value stored by a putfield instruction must be compatible with the descriptor of the referenced field (4.3.2). If the field descriptor type is boolean, byte, char, short, or int, then the value must be an int. If the field descriptor type is float, long, or double, then the value must be a float, long, or double, respectively. If the field descriptor type is a reference type, then the value must be a value of a type that is assignment compatible (JLS §5.2) with the field descriptor type. If the field is final, it must be declared in the current class, and the instruction must occur in an instance initialization method of the current class (2.9.1).

The value and objectref are popped from the operand stack.

The objectref must be of type reference but not an array type.

If the value is of type int and the field descriptor type is boolean, then the int value is narrowed by taking the bitwise AND of value and 1, resulting in value'. Otherwise, the value undergoes value set conversion (2.8.3), resulting in value'.

The referenced field in objectref is set to value'.

Linking Exceptions

During resolution of the symbolic reference to the field, any of the exceptions pertaining to field resolution (5.4.3.2) can be thrown.

Otherwise, if the resolved field is a static field, putfield throws an IncompatibleClassChangeError.

Otherwise, if the resolved field is final, it must be declared in the current class, and the instruction must occur in an instance initialization method of the current class. Otherwise, an IllegalAccessError is thrown.

Run-time Exception

Otherwise, if objectref is null, the putfield instruction throws a NullPointerException.

putstatic

Operation

Set static field in class

Format

putstatic
indexbyte1
indexbyte2

Forms

putstatic = 179 (0xb3)

Operand Stack

..., value

...

Description

The unsigned indexbyte1 and indexbyte2 are used to construct an index into the run-time constant pool of the current class (2.6), where the value of the index is (indexbyte1 << 8) | indexbyte2. The run-time constant pool entry at the index must be a symbolic reference to a field (5.1), which gives the name and descriptor of the field as well as a symbolic reference to the class, or interface, or array type in which the field is to be found. The referenced field is resolved (5.4.3.2).

On successful resolution of the field, the class or interface that declared the resolved field is initialized if that class or interface has not already been initialized (5.5).

The type of a value stored by a putstatic instruction must be compatible with the descriptor of the referenced field (4.3.2). If the field descriptor type is boolean, byte, char, short, or int, then the value must be an int. If the field descriptor type is float, long, or double, then the value must be a float, long, or double, respectively. If the field descriptor type is a reference type, then the value must be a value of a type that is assignment compatible (JLS §5.2) with the field descriptor type. If the field is final, it must be declared in the current class or interface, and the instruction must occur in the class or interface initialization method of the current class or interface (2.9.2).

The value is popped from the operand stack.

If the value is of type int and the field descriptor type is boolean, then the int value is narrowed by taking the bitwise AND of value and 1, resulting in value'. Otherwise, the value undergoes value set conversion (2.8.3), resulting in value'.

The referenced field in the class or interface is set to value'.

Linking Exceptions

During resolution of the symbolic reference to the class or interface field, any of the exceptions pertaining to field resolution (5.4.3.2) can be thrown.

Otherwise, if the resolved field is not a static (class) field or an interface field, putstatic throws an IncompatibleClassChangeError.

Otherwise, if the resolved field is final, it must be declared in the current class or interface, and the instruction must occur in the class or interface initialization method of the current class or interface. Otherwise, an IllegalAccessError is thrown.

Run-time Exception

Otherwise, if execution of this putstatic instruction causes initialization of the referenced class or interface, putstatic may throw an Error as detailed in 5.5.

Notes

A putstatic instruction may be used only to set the value of an interface field on the initialization of that field. Interface fields may be assigned to only once, on execution of an interface variable initialization expression when the interface is initialized (5.5, JLS §9.3.1).