This document proposes changes to the Java Virtual Machine Specification to support a prototype of value classes—classes for which primitive-like non-reference value instances can be created and operated on.

Broad goals of these changes include:

2.2 Data Types

Like the Java programming language, the The Java Virtual Machine operates on two kinds of types: primitive types direct value 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 direct 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 Direct values need not be tagged or otherwise be inspectable to determine their types at run time, or to be distinguished from reference 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 one or more reference types, including the type Object. Values of type reference reference types 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 references.

Certain classes may instead support direct value class instances. These class instances are similar to objects, but do not allow field mutation, locking, or other identity-based operations. A direct value class instance has exactly one type, the direct value type of the class it instantiates.

2.3 Primitive Types Direct Value Types and Values

The direct value types are the primitive types and the direct value class types.

The primitive data types supported by the Java Virtual Machine are the numeric types, the boolean type (2.3.4), and the returnAddress type (2.3.3).

The numeric types consist of the integral types (2.3.1) and the floating-point types (2.3.2).

...

The values of the boolean type encode the truth values true and false, and the default value is false.

The First Edition of The Java® Virtual Machine Specification did not consider boolean to be a Java Virtual Machine type. However, boolean values do have limited support in the Java Virtual Machine. The Second Edition of The Java® Virtual Machine Specification clarified the issue by treating boolean as a type.

The values of the returnAddress type are pointers to the opcodes of Java Virtual Machine instructions. Of the primitive types, only the returnAddress type is not directly associated with a Java programming language type.

Direct value class types are described by value classes. The values of a direct value class type are direct values that are instances of the class. They can be thought of as compositions of values of primitive or reference types, with components stored in fields.

2.3.5 Direct Value Class Types

Every value class has a corresponding direct value class type. Value classes are derived from value-capable classes (4.7.25).

The default value of a direct value class type is a class instance whose fields store the default values of their respective types. There is no special null value of a direct value class type.

2.4 Reference Types and Values

There are three kinds of reference reference types: reference class types, array types, and interface types. Their values are references to dynamically created class instances, arrays, or class instances or arrays that implement interfaces, respectively reference class instances and arrays.

Note that arrays can be instances of the class type Object. No need to get overly-specific here.

Every class (4.1) that is not a value class has a corresponding reference class type. Every interface (4.1) has a corresponding interface type.

An array type consists of a component type with a single dimension (whose length is not given by the type). The component type of an array type may itself be an array type. If, starting from any array type, one considers its component type, and then (if that is also an array type) the component type of that type, and so on, eventually one must reach a component type that is not an array type; this is called the element type of the array type. The element type of an array type is necessarily either a primitive type, or a class type, or an interface type some non-array type.

A reference reference value may also be the special null reference, a reference to no object, which will be denoted here by null. The null reference initially has no run-time type, but may be cast to any type. The default value of a reference type all reference types is null.

This specification does not mandate a concrete value encoding null.

2.5.3 Heap

The Java Virtual Machine has a heap that is shared among all Java Virtual Machine threads. The heap is the run-time data area from which memory for all reference class instances and arrays is allocated. Memory for direct value class instances may also be allocated from the heap (2.7).

...

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 direct value class instance; or a reference. 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.7 Representation of Objects Class Instances and Arrays

The Java Virtual Machine does not mandate any particular internal structure for objects class instances or arrays.

The Java Virtual Machine does not mandate whether direct value class instances are stored in the Java Virtual Machine stack (2.5.2) or dynamically allocated in the heap (2.5.3).

In some of Oracle's implementations of the Java Virtual Machine, a reference to a class instance is a pointer to a handle that is itself a pair of pointers: one to a table containing the methods of the object and a pointer to the Class object that represents the type of the object, and the other to the memory allocated from the heap for the object data.

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 (iload) loads the contents of a local variable, which must be an int, onto the operand stack. The fload instruction (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, and d for double and a for reference. Instructions prefixed with a operate on references, and instructions prefixed with v operate on direct value class instances; where necessary, the specific reference type or direct value class type expected is given as an argument to the instruction. 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 value class
Tipush bipush sipush
Tconst constant bipush sipush iconst lconst fconst dconst aconst vdefault
Tload iload lload fload dload aload vload
Tstore istore lstore fstore dstore astore vstore
Tinc iinc
Taload baload saload iaload laload faload daload caload aaload vaload
Tastore bastore sastore iastore lastore fastore dastore castore aastore vastore
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
a2T vunbox
v2T vbox
Tcmp lcmp
Tcmpl fcmpl dcmpl
Tcmpg fcmpg dcmpg
if_TcmpOP if_icmpOP if_acmpOP
Treturn ireturn lreturn freturn dreturn areturn vreturn

The mapping between Java Virtual Machine actual heap types and Java Virtual Machine computational stack 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 and Computational Heap and stack types in the Java Virtual Machine

Actual Heap type Computational Stack type Category
boolean int 1
byte int 1
char int 1
short int 1
int int 1
float float 1
reference reference T reference reference T 1
value class T value class T 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.

...

2.11.4 Type Conversion Instructions

The type conversion instructions allow conversion between Java Virtual Machine numeric types. These may be used to implement explicit conversions in user code or to mitigate the lack of orthogonality in the instruction set of the Java Virtual Machine.

The Java Virtual Machine directly supports the following widening numeric conversions:

The widening numeric conversion instructions are i2l, i2f, i2d, l2f, l2d, and f2d. The mnemonics for these opcodes are straightforward given the naming conventions for typed instructions and the punning use of 2 to mean "to." For instance, the i2d instruction converts an int value to a double.

...

The Java Virtual Machine also directly supports the following narrowing numeric conversions:

The narrowing numeric conversion instructions are i2b, i2c, i2s, l2i, f2i, f2l, d2i, d2l, and d2f. A narrowing numeric conversion can result in a value of different sign, a different order of magnitude, or both; it may thereby lose precision.

...

The Java Virtual Machine also supports conversion between reference class instances and direct value class instances.

If a value class V is derived from a value-capable class C, a direct value class instance of V may be converted to a reference to an instance of C with the vbox instruction. A reference to an instance of C may be converted to a direct value class instance of V with the vunbox instruction.

2.11.5 Object Class Instance and Array Creation and Manipulation

Although both class instances and arrays are objects, the Java Virtual Machine creates and manipulates class instances and arrays using distinct sets of instructions:

Reference-typed class instances are created and manipulated with the following instructions:

Reference-typed class instances can also be used to invoke instance methods (invokevirtual, invokeinterface, invokespecial: 2.11.8), throw exceptions (athrow: 2.11.9), and perform locking (monitorenter, monitorexit: 2.11.10).

Direct value class instances are created and manipulated with the following instructions:

Arrays are created and manipulated with the following instructions:

Classes and interface also have static fields, available without operating on a specific class instance. These fields are accessed with getstatic and putstatic.

The static methods of a class or interface are invoked with invokestatic and invokedynamic (2.11.8).

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, and vreturn. In addition, the return instruction is used to return from methods declared to be void, instance initialization methods, and class or interface initialization methods.

4.1 The ClassFile Structure

A class file consists of a single ClassFile structure:

ClassFile {
    u4             magic;
    u2             minor_version;
    u2             major_version;
    u2             constant_pool_count;
    cp_info        constant_pool[constant_pool_count-1];
    u2             access_flags;
    u2             this_class;
    u2             super_class;
    u2             interfaces_count;
    u2             interfaces[interfaces_count];
    u2             fields_count;
    field_info     fields[fields_count];
    u2             methods_count;
    method_info    methods[methods_count];
    u2             attributes_count;
    attribute_info attributes[attributes_count];
}

The items in the ClassFile structure are as follows:

magic

The magic item supplies the magic number identifying the class file format; it has the value 0xCAFEBABE.

minor_version, major_version

The values of the minor_version and major_version items are the minor and major version numbers of this class file. Together, a major and a minor version number determine the version of the class file format. If a class file has major version number M and minor version number m, we denote the version of its class file format as M.m. Thus, class file format versions may be ordered lexicographically, for example, 1.5 < 2.0 < 2.1.

A Java Virtual Machine implementation can support a class file format of version v if and only if v lies in some contiguous range Mi.0 ≤ v ≤ Mj.m. The release level of the Java SE platform to which a Java Virtual Machine implementation conforms is responsible for determining the range.

A Java Virtual Machine implementation determines which version numbers it can support.

Oracle's Java Virtual Machine implementation in JDK release 1.0.2 supports class file format versions 45.0 through 45.3 inclusive. JDK releases 1.1.* support class file format versions in the range 45.0 through 45.65535 inclusive. For k ≥ 2, JDK release 1.k supports class file format versions in the range 45.0 through 44+k.0 inclusive.

Oracle's Java Virtual Machine implementations have supported class file versions according to the following chart:

JDK Release Supported Class File Versions
1.0.2 45.0-45.3
1.1 45.0-45.65535
1.2 45.0-46.0
1.3 45.0-47.0
1.4 45.0-48.0
5 45.0-49.0
6 45.0-50.0
7 45.0-51.0
8 45.0-52.0
9 45.0-53.0
10 {45-54}.0, 54.1

Version 54.1 class files are intended to be supported only by implementations of Java SE 10.

We intend for JVMs to no longer support a contiguous range of version numbers, but rather to support 45.0, 46.0, ..., M.0, along with a designated set of M.n version numbers. (It may also be necessary to support some other historical minor versions, such as instances of 45.m where m ≠ 0?)

It's not yet clear what the relationship is between specifications and the choice to support specific version numbers.

constant_pool_count

The value of the constant_pool_count item is equal to the number of entries in the constant_pool table plus one. A constant_pool index is considered valid if it is greater than zero and less than constant_pool_count, with the exception for constants of type long and double noted in 4.4.5.

constant_pool[]

The constant_pool is a table of structures (4.4) representing various string constants, class and interface names, field names, and other constants that are referred to within the ClassFile structure and its substructures. The format of each constant_pool table entry is indicated by its first "tag" byte.

The constant_pool table is indexed from 1 to constant_pool_count - 1.

access_flags

The value of the access_flags item is a mask of flags used to denote access permissions to and properties of this class or interface. The interpretation of each flag, when set, is specified in Table 4.1-A.

Table 4.1-A. Class access and property modifiers

Flag name Value Interpretation
ACC_PUBLIC 0x0001 Declared public; may be accessed from outside its package.
ACC_FINAL 0x0010 Declared final; no subclasses allowed.
ACC_SUPER 0x0020 Treat superclass methods specially when invoked by the invokespecial instruction.
ACC_VALUE 0x0100 Is a value class.
ACC_INTERFACE 0x0200 Is an interface, not a class.
ACC_ABSTRACT 0x0400 Declared abstract; must not be instantiated.
ACC_SYNTHETIC 0x1000 Declared synthetic; not present in the source code.
ACC_ANNOTATION 0x2000 Declared as an annotation type.
ACC_ENUM 0x4000 Declared as an enum type.

An interface is distinguished by the ACC_INTERFACE flag being set. If the ACC_INTERFACE flag is not set, this class file defines a class, not an interface.

If the ACC_INTERFACE flag is set, the ACC_ABSTRACT flag must also be set, and the ACC_FINAL, ACC_SUPER, and ACC_ENUM flags set must not be set.

If the ACC_INTERFACE flag is not set, any of the other flags in Table 4.1-A may be set except ACC_ANNOTATION. However, such a class file must not have both its ACC_FINAL and ACC_ABSTRACT flags set (JLS 8.1.1.2).

A value class is distinguished by the ACC_VALUE flag. The ACC_VALUE flag should only be set in classes derived from value-capable classes (4.7.25). In any other class file whose version number is 54.1, the flag must not be set. In any class file whose version number is not 54.1, the flag should not be set and is treated as if it were not set.

The ACC_SUPER flag indicates which of two alternative semantics is to be expressed by the invokespecial instruction (invokespecial) if it appears in this class or interface. Compilers to the instruction set of the Java Virtual Machine should set the ACC_SUPER flag. In Java SE 8 and above, the Java Virtual Machine considers the ACC_SUPER flag to be set in every class file, regardless of the actual value of the flag in the class file and the version of the class file.

The ACC_SUPER flag exists for backward compatibility with code compiled by older compilers for the Java programming language. In JDK releases prior to 1.0.2, the compiler generated access_flags in which the flag now representing ACC_SUPER had no assigned meaning, and Oracle's Java Virtual Machine implementation ignored the flag if it was set.

The ACC_SYNTHETIC flag indicates that this class or interface was generated by a compiler and does not appear in source code.

An annotation type must have its ACC_ANNOTATION flag set. If the ACC_ANNOTATION flag is set, the ACC_INTERFACE flag must also be set.

The ACC_ENUM flag indicates that this class or its superclass is declared as an enumerated type.

All bits of the access_flags item not assigned in Table 4.1-A are reserved for future use. They should be set to zero in generated class files and should be ignored by Java Virtual Machine implementations.

this_class

The value of the this_class item must be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_Class_info structure (4.4.1) representing the class or interface type of the class or interface defined by this class file.

super_class

For a class, the value of the super_class item either must be zero or must be a valid index into the constant_pool table. If the value of the super_class item is nonzero, the constant_pool entry at that index must be a CONSTANT_Class_info structure representing the direct superclass type of the class defined by this class file. Neither the direct superclass nor any of its superclasses may have the ACC_FINAL flag set in the access_flags item of its ClassFile structure.

If the value of the super_class item is zero, then this class file must represent the class Object, the only class or interface without a direct superclass.

For an interface, the value of the super_class item must always be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_Class_info structure representing the reference class type Object.

interfaces_count

The value of the interfaces_count item gives the number of direct superinterfaces superinterface types of this class or interface type.

interfaces[]

Each value in the interfaces array must be a valid index into the constant_pool table. The constant_pool entry at each value of interfaces[i], where 0 ≤ i < interfaces_count, must be a CONSTANT_Class_info structure representing an interface type that is a direct superinterface type of this class or interface type, in the left-to-right order given in the source for the type class or interface.

...

4.3.2 Field Descriptors

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

FieldDescriptor:

FieldType

FieldType:

BaseType ObjectType ReferenceClassType DirectValueClassType ArrayType

BaseType:

(one of) B C D F I J S Z

ReferenceClassType:

L ClassName ;

DirectValueClassType:

Q ClassName ;

ArrayType:

[ ComponentType FieldType

ComponentType:

FieldType

The characters of BaseType, the L and ; of ObjectType, and the [ of ArrayType The terminal symbols in these productions are all ASCII characters.

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

The interpretation of field descriptors as types is shown in Table 4.3-A. See 2.2, 2.3, and 2.4 for 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 integer integer
J long long integer
L ClassName ; reference Named reference class or interface type an instance of class ClassName
Q ClassName ; Named direct value class type
S short signed short
Z boolean true or false
[ FieldType 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.4.1 The CONSTANT_Class_info Structure

The CONSTANT_Class_info structure is used to represent a class or an interface type (2.2):

The CONSTANT_Class_info structure historically represents classes or interfaces, with a special accomodation for array types. The attribute is closely related to java.lang.Class, which is designed to describe all JVM types, including primitive types and array types. Rather than treat these cases as anamolies, we choose to embrace it: a CONSTANT_Class_info, in general, can represent any type (with a current exception for primitive types). Other parts of the JVM that make use of the structure are responsible for describing, if necessary, the subset of types that are allowed in that context (see, e.g., 4.4.2 and 4.9.1).

Java Virtual Machines may also have distinct internal representations of true classes and interfaces, which correspond to ClassFile structures.

CONSTANT_Class_info {
   u1 tag;
   u2 name_index;
}

The items of the CONSTANT_Class_info structure are as follows:

tag

The tag item has the value CONSTANT_Class (7).

name_index

The value of the name_index item must be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_Utf8_info structure (4.4.7) representing of one of the following forms:

If the class file version number is not 54.1, then the CONSTANT_Utf8_info structure must not represent a direct value class type or an array type with a direct value class type as its element type.

Because arrays are objects, the opcodes anewarray and multianewarray—but not the opcode new—can reference array "classes" via CONSTANT_Class_info structures in the constant_pool table. For such array classes, the name of the class is the descriptor of the array type (4.3.2).

For example, the class name representing the two-dimensional array type int[][] is [[I, while the class name representing the type Thread[] is [Ljava/lang/Thread;.

Examples:

An array type descriptor is valid only if it represents 255 or fewer dimensions.

This assertion is already made in 4.3.2.

The CONSTANT_Class_info structure cannot currently express primitive types. For most uses of CONSTANT_Class_info, this is not a concern because they would consider it an error for a primitive type to appear. Where primitive types are appropriate, there are various workarounds:

4.4.2 The CONSTANT_Fieldref_info, CONSTANT_Methodref_info, and CONSTANT_InterfaceMethodref_info Structures

Fields, methods, and interface methods are represented by similar structures:

CONSTANT_Fieldref_info {
    u1 tag;
    u2 class_index;
    u2 name_and_type_index;
}

CONSTANT_Methodref_info {
    u1 tag;
    u2 class_index;
    u2 name_and_type_index;
}

CONSTANT_InterfaceMethodref_info {
    u1 tag;
    u2 class_index;
    u2 name_and_type_index;
}

The items of these structures are as follows:

tag

The tag item of a CONSTANT_Fieldref_info structure has the value CONSTANT_Fieldref (9).

The tag item of a CONSTANT_Methodref_info structure has the value CONSTANT_Methodref (10).

The tag item of a CONSTANT_InterfaceMethodref_info structure has the value CONSTANT_InterfaceMethodref (11).

class_index

The value of the class_index item must be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_Class_info structure (4.4.1) representing a class or interface type that has the field or method as a member.

The class_index item of a CONSTANT_Methodref_info structure must be a reference class type, not an interface type or a direct value class type.

The class_index item of a CONSTANT_InterfaceMethodref_info structure must be an interface type.

The class_index item of a CONSTANT_Fieldref_info structure may be either a reference class type or an interface type. In a class file whose version number is 54.1, the class_index item may also be a direct value class type.

name_and_type_index

The value of the name_and_type_index item must be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_NameAndType_info structure (4.4.6). This constant_pool entry indicates the name and descriptor of the field or method.

In a CONSTANT_Fieldref_info, the indicated descriptor must be a field descriptor (4.3.2). Otherwise, the indicated descriptor must be a method descriptor (4.3.3). If the name of the method of a CONSTANT_Methodref_info structure begins with a '<' ('\u003c'), then the name must be the special name <init>, representing an instance initialization method (2.9). The return type of such a method must be void.

4.4.6 The CONSTANT_NameAndType_info Structure

The CONSTANT_NameAndType_info structure is used to represent a field or method, without indicating which class or interface type it belongs to:

CONSTANT_NameAndType_info {
    u1 tag;
    u2 name_index;
    u2 descriptor_index;
}

The items of the CONSTANT_NameAndType_info structure are as follows:

tag

The tag item of the CONSTANT_NameAndType_info structure has the value CONSTANT_NameAndType (12).

name_index

The value of the name_index item must be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_Utf8_info structure (4.4.7) representing either the special method name <init> (2.9) or a valid unqualified name denoting a field or method (4.2.2).

descriptor_index

The value of the descriptor_index item must be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_Utf8_info structure (4.4.7) representing a valid field descriptor or method descriptor (4.3.2, 4.3.3).

If the class file version number is not 54.1 then the CONSTANT_Utf8_info structure must not mention a direct value class type as a field descriptor, parameter descriptor, return descriptor, or element type of an array type.

4.4.9 The CONSTANT_MethodType_info Structure

The CONSTANT_MethodType_info structure is used to represent a method type:

CONSTANT_MethodType_info {
    u1 tag;
    u2 descriptor_index;
}

The items of the CONSTANT_MethodType_info structure are as follows:

tag

The tag item of the CONSTANT_MethodType_info structure has the value CONSTANT_MethodType (16).

descriptor_index

The value of the descriptor_index item must be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_Utf8_info structure (4.4.7) representing a method descriptor (4.3.3).

If the class file version number is not 54.1 then the method descriptor must not mention a direct value class type as a parameter descriptor, return descriptor, or element type of an array type.

4.5 Fields

Each field is described by a field_info structure.

No two fields in one class file may have the same name and descriptor (4.3.2).

The structure has the following format:

field_info {
    u2             access_flags;
    u2             name_index;
    u2             descriptor_index;
    u2             attributes_count;
    attribute_info attributes[attributes_count];
}

The items of the field_info structure are as follows:

access_flags

The value of the access_flags item is a mask of flags used to denote access permission to and properties of this field. The interpretation of each flag, when set, is specified in Table 4.5-A.

...

name_index

The value of the name_index item must be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_Utf8_info structure (4.4.7) which represents a valid unqualified name denoting a field (4.2.2).

descriptor_index

The value of the descriptor_index item must be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_Utf8_info structure (4.4.7) which represents a valid field descriptor (4.3.2).

The field descriptor must not represent a direct value class type.

If the class file version number is not 54.1, then the field descriptor must not mention a direct value class type as an element type of an array type.

Fields in version 54.1 class files are not allowed to hold direct value class instances. They are allowed to hold arrays of direct value class instances.

The intent is to support direct value class-typed fields in a future release.

attributes_count

The value of the attributes_count item indicates the number of additional attributes of this field.

attributes[]

Each value of the attributes table must be an attribute_info structure (4.7).

A field can have any number of optional attributes associated with it.

The attributes defined by this specification as appearing in the attributes table of a field_info structure are listed in Table 4.7-C.

The rules concerning attributes defined to appear in the attributes table of a field_info structure are given in 4.7.

The rules concerning non-predefined attributes in the attributes table of a field_info structure are given in 4.7.1.

4.6 Methods

Each method, including each instance initialization method (2.9) and the class or interface initialization method (2.9), is described by a method_info structure.

No two methods in one class file may have the same name and descriptor (4.3.3).

The structure has the following format:

method_info {
    u2             access_flags;
    u2             name_index;
    u2             descriptor_index;
    u2             attributes_count;
    attribute_info attributes[attributes_count];
}

The items of the method_info structure are as follows:

access_flags

The value of the access_flags item is a mask of flags used to denote access permission to and properties of this method. The interpretation of each flag, when set, is specified in Table 4.6-A.

...

name_index

The value of the name_index item must be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_Utf8_info structure (4.4.7) representing either one of the special method names <init> or <clinit> (2.9), or a valid unqualified name denoting a method (4.2.2).

descriptor_index

The value of the descriptor_index item must be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_Utf8_info structure (4.4.7) which represents a valid method descriptor (4.3.3).

If the class file version number is not 54.1, or if the access_flags of the method has set ACC_NATIVE, then the method descriptor must not mention a direct value class type as a parameter descriptor, return descriptor, or element type of an array type.

attributes_count

The value of the attributes_count item indicates the number of additional attributes of this method.

attributes[]

Each value of the attributes table must be an attribute_info structure (4.7).

A method can have any number of optional attributes associated with it.

The attributes defined by this specification as appearing in the attributes table of a method_info structure are listed in Table 4.7-C.

The rules concerning attributes defined to appear in the attributes table of a method_info structure are given in 4.7.

The rules concerning non-predefined attributes in the attributes table of a method_info structure are given in 4.7.1.

4.7 Attributes

Attributes are used in the ClassFile, field_info, method_info, and Code_attribute structures of the class file format (4.1, 4.5, 4.6, 4.7.3).

All attributes have the following general format:

attribute_info {
   u2 attribute_name_index;
   u4 attribute_length;
   u1 info[attribute_length];
}

For all attributes, the attribute_name_index must be a valid unsigned 16-bit index into the constant pool of the class. The constant_pool entry at attribute_name_index must be a CONSTANT_Utf8_info structure (4.4.7) representing the name of the attribute. The value of the attribute_length item indicates the length of the subsequent information in bytes. The length does not include the initial six bytes that contain the attribute_name_index and attribute_length items.

23 24 attributes are predefined by this specification. They are listed three times, for ease of navigation:

Within the context of their use in this specification, that is, in the attributes tables of the class file structures in which they appear, the names of these predefined attributes are reserved.

Any conditions on the presence of a predefined attribute in an attributes table are specified explicitly in the section which describes the attribute. If no conditions are specified, then the attribute may appear any number of times in an attributes table.

The predefined attributes are categorized into three groups according to their purpose:

  1. Five Six attributes are critical to correct interpretation of the class file by the Java Virtual Machine:

    In a class file of version V, each of these attributes must be recognized and correctly read by an implementation of the Java Virtual Machine if the implementation recognizes class files of version V, and V is at least the version where the attribute was first defined, and the attribute appears in a location where it is defined to appear.

  2. Twelve attributes are critical to correct interpretation of the class file by the class libraries of the Java SE platform:

    Each of these attributes in a class file of version V must be recognized and correctly read by an implementation of the class libraries of the Java SE platform if the implementation recognizes class files of version V, and V is at least the version where the attribute was first defined, and the attribute appears in a location where it is defined to appear.

  3. Six attributes are not critical to correct interpretation of the class file by either the Java Virtual Machine or the class libraries of the Java SE platform, but are useful for tools:

    Use of these attributes by an implementation of the Java Virtual Machine or the class libraries of the Java SE platform is optional. An implementation may use the information that these attributes contain, or otherwise must silently ignore these attributes.

Table 4.7-A. Predefined class file attributes (by section)

Attribute Section class file Java SE
ConstantValue 4.7.2 45.3 1.0.2
Code 4.7.3 45.3 1.0.2
StackMapTable 4.7.4 50.0 6
Exceptions 4.7.5 45.3 1.0.2
InnerClasses [4.7.6] 45.3 1.1
EnclosingMethod [4.7.7] 49.0 5.0
Synthetic [4.7.8] 45.3 1.1
Signature [4.7.9] 49.0 5.0
SourceFile [4.7.10] 45.3 1.0.2
SourceDebugExtension [4.7.11] 49.0 5.0
LineNumberTable [4.7.12] 45.3 1.0.2
LocalVariableTable [4.7.13] 45.3 1.0.2
LocalVariableTypeTable [4.7.14] 49.0 5.0
Deprecated [4.7.15] 45.3 1.1
RuntimeVisibleAnnotations [4.7.16] 49.0 5.0
RuntimeInvisibleAnnotations [4.7.17] 49.0 5.0
RuntimeVisibleParameterAnnotations [4.7.18] 49.0 5.0
RuntimeInvisibleParameterAnnotations [4.7.19] 49.0 5.0
RuntimeVisibleTypeAnnotations [4.7.20] 52.0 8
RuntimeInvisibleTypeAnnotations [4.7.21] 52.0 8
AnnotationDefault [4.7.22] 49.0 5.0
BootstrapMethods [4.7.23] 51.0 7
MethodParameters [4.7.24] 52.0 8
ValueCapableClass 4.7.25 54.0 10

Table 4.7-B. Predefined class file attributes (by class file version)

Attribute class file Java SE Section
ConstantValue 45.3 1.0.2 4.7.2
Code 45.3 1.0.2 4.7.3
Exceptions 45.3 1.0.2 4.7.5
SourceFile 45.3 1.0.2 [4.7.10]
LineNumberTable 45.3 1.0.2 [4.7.12]
LocalVariableTable 45.3 1.0.2 [4.7.13]
InnerClasses 45.3 1.1 [4.7.6]
Synthetic 45.3 1.1 [4.7.8]
Deprecated 45.3 1.1 [4.7.15]
EnclosingMethod 49.0 5.0 [4.7.7]
Signature 49.0 5.0 [4.7.9]
SourceDebugExtension 49.0 5.0 [4.7.11]
LocalVariableTypeTable 49.0 5.0 [4.7.14]
RuntimeVisibleAnnotations 49.0 5.0 [4.7.16]
RuntimeInvisibleAnnotations 49.0 5.0 [4.7.17]
RuntimeVisibleParameterAnnotations 49.0 5.0 [4.7.18]
RuntimeInvisibleParameterAnnotations 49.0 5.0 [4.7.19]
AnnotationDefault 49.0 5.0 [4.7.22]
StackMapTable 50.0 6 4.7.4
BootstrapMethods 51.0 7 [4.7.23]
RuntimeVisibleTypeAnnotations 52.0 8 [4.7.20]
RuntimeInvisibleTypeAnnotations 52.0 8 [4.7.21]
MethodParameters 52.0 8 [4.7.24]
ValueCapableClass 54.0 10 4.7.25

Table 4.7-C. Predefined class file attributes (by location)

Attribute Location class file
SourceFile ClassFile 45.3
InnerClasses ClassFile 45.3
EnclosingMethod ClassFile 49.0
SourceDebugExtension ClassFile 49.0
BootstrapMethods ClassFile 51.0
ValueCapableClass ClassFile 54.0
ConstantValue field_info 45.3
Code method_info 45.3
Exceptions method_info 45.3
RuntimeVisibleParameterAnnotations, RuntimeInvisibleParameterAnnotations method_info 49.0
AnnotationDefault method_info 49.0
MethodParameters method_info 52.0
Synthetic ClassFile, field_info, method_info 45.3
Deprecated ClassFile, field_info, method_info 45.3
Signature ClassFile, field_info, method_info 49.0
RuntimeVisibleAnnotations, RuntimeInvisibleAnnotations ClassFile, field_info, method_info 49.0
LineNumberTable Code 45.3
LocalVariableTable Code 45.3
LocalVariableTypeTable Code 49.0
StackMapTable Code 50.0
RuntimeVisibleTypeAnnotations, RuntimeInvisibleTypeAnnotations ClassFile, field_info, method_info, Code 52.0

4.7.3 The Code Attribute

...

catch_type

If the value of the catch_type item is nonzero, it must be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_Class_info structure (4.4.1) representing a reference class type of exceptions that this exception handler is designated to catch. The exception handler will be called only if the thrown exception is a reference to an instance of the given class or one of its subclasses.

The verifier checks that the reference class type is Throwable or a subclass subtype of Throwable (4.9.2).

If the value of the catch_type item is zero, this exception handler is called for all exceptions.

This is used to implement finally ([3.13]).

...

4.7.4 The StackMapTable Attribute

...

...

4.7.5 The Exceptions Attribute

...

exception_index_table[]

Each value in the exception_index_table array must be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_Class_info structure (4.4.1) representing a reference class type that this method is declared to throw.

...

4.7.25 The ValueCapableClass Attribute

The ValueCapableClass attribute is an optional fixed-length attribute in the attributes table of a ClassFile structure (4.1). A class marked with a ValueCapableClass attribute allows the Java Virtual Machine to derive a value class (2.2) from the class.

This implies that the flags ACC_INTERFACE and ACC_ABSTRACT should not be set.

A version 54.0 class file can declare a value-capable class. However, loading of a derived value class (5.3) is only performed by a Java Virtual Machine implementation that supports version 54.1 class files. Other JVM implementations will ignore the attribute.

The ValueCapableClass attribute has the following format:

ValueCapableClass_attribute {
    u2 attribute_name_index;
    u4 attribute_length;
}

The items of the ValueCapableClass_attribute structure are as follows:

attribute_name_index

The value of the attribute_name_index item must be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_Utf8_info structure (4.4.7) representing the string "ValueCapableClass".

attribute_length

The value of the attribute_length item must be zero.

4.9.1 Static Constraints

The static constraints on a class file are those defining the well-formedness of the file. These constraints have been given in the previous sections, except for static constraints on the code in the class file. The static constraints on the code in a class file specify how Java Virtual Machine instructions must be laid out in the code array and what the operands of individual instructions must be.

The static constraints on the instructions in the code array are as follows:

The static constraints on the operands of instructions in the code array are as follows:

4.9.2 Structural Constraints

The structural constraints on the code array specify constraints on relationships between Java Virtual Machine instructions. The structural constraints are as follows:

...

...

4.10.1 Verification by Type Checking

...

classIsTypeSafe(Class) :-

classClassName(Class, Name),
classDefiningLoader(Class, L),
superclassChain(Name, L, Chain),
loadedSuperclasses(Class, Supers),
Chain Supers = [],
classSuperClassName(Class, SuperclassName),
classDefiningLoader(Class, L),
loadedClass(SuperclassName, L, Superclass),
classIsNotFinal(Superclass),
classMethods(Class, Methods),
checklist(methodIsTypeSafe(Class), Methods).

classIsTypeSafe(Class) :-

classClassName(Class, 'java/lang/Object'),
classDefiningLoader(Class, L),
isBootstrapLoader(L),
classMethods(Class, Methods),
checklist(methodIsTypeSafe(Class), Methods).

Changes to 4.10.1.1 and 4.10.1.2, below, use loaded classes rather than verification types to represent the "superclass chain" of a class. This is purely to improve presentation.

...

4.10.1.1 Accessors for Java Virtual Machine Artifacts

We stipulate the existence of 30 Prolog predicates ("accessors") that have certain expected behavior but whose formal definitions are not given in this specification.

classClassName(Class, ClassName)

Extracts the name, ClassName, of the class Class.

classIsInterface(Class)

True iff the class, Class, is an interface.

classIsValueClass(Class)

True iff the class, Class, is a value class.

classIsNotFinal(Class)

True iff the class, Class, is not a final class.

...

parseFieldDescriptor(Descriptor, Type)

Converts a field descriptor, Descriptor, into the corresponding verification type Type (4.10.1.2).

The verification type derived from types byte, short, boolean, and char is int.

parseMethodDescriptor(Descriptor, ArgTypeList, ReturnType)

Converts a method descriptor, Descriptor, into a list of verification types, ArgTypeList, corresponding to the method argument types, and a verification type, ReturnType, corresponding to the return type.

The verification type derived from types byte, short, boolean, and char is int. A void return is represented with the special symbol void.

parseConstantClassType(Name, Type)

Expresses the type given by a CONSTANT_Class_info as a verification type.

parseCodeAttribute(Class, Method, FrameSize, MaxStack, ParsedCode, Handlers, StackMap)

Extracts the instruction stream, ParsedCode, of the method Method in Class, as well as the maximum operand stack size, MaxStack, the maximal number of local variables, FrameSize, the exception handlers, Handlers, and the stack map StackMap.

The representation of the instruction stream and stack map attribute must be as specified in 4.10.1.3 and 4.10.1.4.

samePackageName(Class1, Class2)

True iff the package names of Class1 and Class2 are the same.

differentPackageName(Class1, Class2)

True iff the package names of Class1 and Class2 are different.

The above accessors are used to define loadedSuperclasses, which produces a list of a class's superclasses.

loadedSuperclasses(Class, [ Superclass | Rest ]) :-

classSuperClassName(Class, SuperclassName),
classDefiningLoader(Class, L),
loadedClass(SuperclassName, L, Superclass),
loadedSuperclasses(Superclass, Rest).

loadedSuperclasses(Class, []) :-

classClassName(Class, 'java/lang/Object'),
classDefiningLoader(Class, BL),
isBootstrapLoader(BL).

The loadedSuperclasses predicate replaces superclassChain (4.10.1.2), which had the same effect, but produced a list of class types rather than loaded classes. (Despite the change in representation, all superclasses are loaded in either case.)

Given the introduction of separate reference and direct value class types, it's unnecessarily confusing to continue to use class type structures outside of the scope of their intended application, the representation of types. Instead, the best way to represent a class is with a real loaded class.

When type checking a method's body, it is convenient to access information about the method. For this purpose, we define an environment, a six-tuple consisting of:

We specify accessors to extract information from the environment.

allInstructions(Environment, Instructions) :-

Environment = environment(_Class, Method, ReturnType, Instructions, , ).

exceptionHandlers(Environment, Handlers) :-

_Environment = environment(_Class, _Method, ReturnType, Instructions, , Handlers).

maxOperandStackLength(Environment, MaxStack) :-

_Environment = environment(_Class, _Method, _ReturnType, _Instructions, MaxStack, Handlers).

currentClassLoader(Environment, Loader) :-

Environment = environment(Class, _Method, _ReturnType, _Instructions, _, _),
classDefiningLoader(Class, L).

thisClass(Environment, Class) :-

Environment = environment(Class, _Method, _ReturnType, _Instructions, _, _).

thisClass thisType(Environment, class refclass(ClassName, L)) :-

Environment = environment(Class, _Method, _ReturnType, _Instructions, _, _),
\+ classIsValueClass(Class),
classDefiningLoader(Class, L),
classClassName(Class, ClassName).

thisType(Environment, valclass(ClassName, L)) :-

Environment = environment(Class, _Method, _ReturnType, _Instructions, _, _),
classIsValueClass(Class),
classDefiningLoader(Class, L),
classClassName(Class, ClassName).

thisMethodReturnType(Environment, ReturnType) :-

Environment = environment(_Class, Method, ReturnType, Instructions, , ).

We specify additional predicates to extract higher-level information from the environment.

offsetStackFrame(Environment, Offset, StackFrame) :-

allInstructions(Environment, Instructions), member(stackMap(Offset, StackFrame), Instructions).

currentClassLoader(Environment, Loader) :-

thisClass(Environment, class(_, Loader)).

Finally, we specify a general predicate used throughout the type rules:

notMember(_, []). notMember(X, [A | More]) :- X = A, notMember(X, More).

The principle guiding the determination as to which accessors are stipulated and which are fully specified is that we do not want to over-specify the representation of the class file. Providing specific accessors to the Class or Method term would force us to completely specify the format for a Prolog term representing the class file.

4.10.1.2 Verification Type System

The type checker enforces a type system based upon a hierarchy of verification types, illustrated below.

Verification type hierarchy:

                             top
                    _________/\____________
                   /                       \
                  /                         \
              oneWord                         twoWord
           /   |   |   \                     /       \
          /    |   |    \                   /         \
  valueClass  int float  reference        long        double
      |                  /     \
      |                 /       \____________
+-----------+          /                     \
|each direct|         /                       \
|value class|   uninitialized                Object
|type       |    /         \                     \
+-----------+   /           \                     \
    uninitializedThis  uninitialized(offset)     +------------------+
                                                 |  reference type  |
                                                 |  hierarchy       |
                                                 +------------------+
                                                          |
                                                          |
                                                         null

Changes to this chart:

Most verification types have a direct correspondence with the primitive direct value and reference types described in 2.2 and represented by field descriptors in Table 4.3-A:

The primitive types byte, char, short, and boolean (field descriptors B, C, S, Z) have no corresponding verification type, because their values on the operand stack are implicitly converted to type int. However, arrays of these primitive types do have corresponding verification types.

The verification types uninitializedThis and uninitialized(Offset) represent references to objects created with new that have not yet been initialized ([2.9.2]). The verification type uninitialized(Offset) is represented by applying the functor uninitialized to an argument representing the numerical value of the Offset.

Other verification types are represented in Prolog as atoms whose name denotes the verification type in question.

The subtyping rules for verification types are as follows. Subtyping is reflexive.

isAssignable(X, X).

The verification types which are not reference types in the Java programming language have subtype rules of the form:

isAssignable(v, X) :- isAssignable(the_direct_supertype_of_v, X).

That is, v is a subtype of X if the direct supertype of v is a subtype of X. The rules are:

A type is a subtype of some other type, X, if its direct supertype is a subtype of X.

isAssignable(oneWord, top).
isAssignable(twoWord, top).

isAssignable(int, X) :- isAssignable(oneWord, X).
isAssignable(float, X) :- isAssignable(oneWord, X).
isAssignable(long, X) :- isAssignable(twoWord, X).
isAssignable(double, X) :- isAssignable(twoWord, X).

isAssignable(valueClass, X) :- isAssignable(oneWord, X).
isAssignable(valclass(_, _), X) :- isAssignable(valueClass, X).

isAssignable(reference, X) :- isAssignable(oneWord, X).
isAssignable(refclass(_, _), X) :- isAssignable(reference, X).
isAssignable(arrayOf(_), X) :- isAssignable(reference, X).

isAssignable(uninitialized, X) :- isAssignable(reference, X).
isAssignable(uninitializedThis, X) :- isAssignable(uninitialized, X).
isAssignable(uninitialized(_), X) :- isAssignable(uninitialized, X).

The type null is a subtype of all reference types.

isAssignable(null, refclass(_, _)).
isAssignable(null, arrayOf(_)).
isAssignable(null, X) :- isAssignable(class('java/lang/Object', BL), X), isBootstrapLoader(BL).
isAssignable(null, X) :- isAssignable(reference, X).

These subtype rules are not necessarily the most obvious formulation of subtyping. There is a clear split between subtyping rules for reference types in the Java programming language among reference types, and rules for the remaining verification types. The split allows us to state general subtyping relations between Java programming language reference types and other verification types. These relations hold independently of a Java reference type's position in the type hierarchy, and help to prevent excessive class loading by a Java Virtual Machine implementation. For example, we do not want to start climbing the Java superclass hierarchy in response to a query of the form refclass(foo, L) <: twoWord.

We also have a rule that says subtyping is reflexive, so together these rules cover most verification types that are not reference types in the Java programming language.

Subtype rules for the reference types in the Java programming language are specified recursively with isJavaAssignable isWideningReference.

isAssignable(class(X, Lx), class(Y, Ly)) :-

isJavaAssignable(class(X, Lx), class(Y, Ly)).

isAssignable(arrayOf(X), class(Y, L)) :-

isJavaAssignable(arrayOf(X), class(Y, L)).

isAssignable(arrayOf(X), arrayOf(Y)) :-

isJavaAssignable(arrayOf(X), arrayOf(Y)).

isAssignable(From, To) :- isWideningReference(From, To).

The isWideningReference predicate is only defined for reference types, and will fail to match any non-reference inputs. So it's unnecessary to restrict the form of the inputs to these isAssignable rules in order to avoid testing non-reference types.

For assignments, interfaces are treated like Object. The verifier allows any reference type to be widened to an interface type.

isWideningReference(refclass(_, _), refclass(To, L)) :-

loadedClass(To, L, ToClass),
classIsInterface(ToClass).

isWideningReference(arrayOf(_), refclass(To, L)) :-

loadedClass(To, L, ToClass),
classIsInterface(ToClass).

This approach is less strict than the Java Programming Language, which will not allow an assignment to an interface unless the type is statically known to implement or extend the interface. The Java Virtual Machine instead uses a run-time check to ensure that invocations of interface methods actually operate on objects that implement the interface (invokeinterface). But there is no requirement that a reference stored by a local variable of an interface type refers to an object that actually implements that interface.

A reference class type can be widened to another reference class type if that type refers to the loaded class or one of its superclasses.

isJavaAssignable(From, To) :- isJavaSubclassOf(From, To).

isWideningReference(refclass(ClassName, L1), refclass(ClassName, L2)) :-

L1 \= L2,
loadedClass(ClassName, L1, Class),
loadedClass(ClassName, L2, Class).

isWideningReference(refclass(From, L1), refclass(To, L2)) :-

loadedClass(From, L1, FromClass),
loadedClass(To, L2, ToClass),
loadedSuperclasses(FromClass, Supers)
member(ToClass, Supers).

A bug in the previous rules failed to allow the same class to be treated as a subtype of itself when referenced in the context of different initiating class loaders. It's not clear if this has any practical impact (are subtype tests ever performed between types referenced from different classes?), but the first rule above addresses it.

Array types are subtypes of Object. The intent is also that array types are subtypes of Cloneable and java.io.Serializable.

isJavaAssignable(arrayOf(_), class('java/lang/Object', BL)) :- isBootstrapLoader(BL).
isJavaAssignable(arrayOf(_), X) :- isArrayInterface(X).
isArrayInterface(class('java/lang/Cloneable', BL)) :- isBootstrapLoader(BL).
isArrayInterface(class('java/io/Serializable', BL)) :- isBootstrapLoader(BL).

isWideningReference(arrayOf(_), refclass('java/lang/Object', L)) :-

loadedClass('java/lang/Object', L, ObjectClass),
classDefiningLoader(ObjectClass, BL),
isBootstrapLoader(BL).

A bug in the previous rules fails to treat array types as subtypes of class('java/lang/Object', L) unless L is the bootstrap loader. Since L is the initiating loader, that rule failed to support the common case of java/lang/Object being referenced outside of bootstrap classes.

The previous rules also fail to allow an array type to be treated as a subtype of an arbitrary interface type. In practice, it is possible to, say, pass an array as an argument to a method expecting a Runnable. The earlier rules for interface types address this, making it unnecessary to single out Cloneable and Serializable for special treatment.

Subtyping between arrays of primitive type is the identity relation.

isJavaAssignable(arrayOf(X), arrayOf(Y)) :-

atom(X),
atom(Y),
X = Y.

Subtyping between arrays of reference type is covariant.

isWideningReference(arrayOf(X), arrayOf(Y)) :-

compound(X),
compound(Y),
isWideningReference(X, Y).

The subtyping rule for arrays of primitive types is an identity conversion, not a widening; and it is already covered by the reflexive rule for isAssignable.

The subtyping rule for arrays of reference types does not need to check that the inputs are reference types—if not, isWideningReference will not succeed.

Subclassing is reflexive.

isJavaSubclassOf(class(SubclassName, L), class(SubclassName, L)).

isJavaSubclassOf(class(SubclassName, LSub), class(SuperclassName, LSuper)) :-

superclassChain(SubclassName, LSub, Chain),
member(class(SuperclassName, L), Chain),
loadedClass(SuperclassName, L, Sup),
loadedClass(SuperclassName, LSuper, Sup).

This relation is expressed directly with isWideningReference, above. No need to introduce another predicate.

superclassChain(ClassName, L, [class(SuperclassName, Ls) | Rest]) :-

loadedClass(ClassName, L, Class),
classSuperClassName(Class, SuperclassName),
classDefiningLoader(Class, Ls),
superclassChain(SuperclassName, Ls, Rest).

superclassChain('java/lang/Object', L, []) :-

loadedClass('java/lang/Object', L, Class), classDefiningLoader(Class, BL), isBootstrapLoader(BL).

This predicate is moved to 4.10.1.1 and renamed loadedSuperclasses.

4.10.1.3 Instruction Representation

...

A few instructions have operands that are constant pool entries representing fields, methods, and dynamic call sites. In the constant pool, a field is represented by a CONSTANT_Fieldref_info structure, a method is represented by a CONSTANT_InterfaceMethodref_info structure (for an interface's method) or a CONSTANT_Methodref_info structure (for a class's method), and a dynamic call site is represented by a CONSTANT_InvokeDynamic_info structure (4.4.2, 4.4.10). Such structures are represented as functor applications of the form:

For clarity, we assume that field and method descriptors (4.3.2, 4.3.3) are mapped into more readable names: the leading L and trailing ; are dropped from class names, and the BaseType characters used for primitive types are mapped to the names of those types.

The descriptor should always be processed with parseFieldDescriptor, so its format doesn't need to be specified.

For example, a getfield instruction whose operand was an index into the constant pool that refers to a field foo of type F in class reference class type Bar would be represented as getfield(field('Bar' classConstant('Bar'), 'foo', 'F')).

...

4.10.1.6 Type Checking Methods with Code

...

instanceMethodInitialThisType(Class, Method, uninitializedThis) :-

methodName(Method, '<init>'),
classClassName(Class, ClassName),
classDefiningLoader(Class, CurrentLoader),
superclassChain(ClassName, CurrentLoader, Chain),
loadedSuperclasses(Class, Supers),
Chain Supers = [].

...

4.10.1.8 Type Checking for protected Members

Changes to the section involve:

All instructions that access members must contend with the rules concerning protected members. This section describes the protected check that corresponds to JLS 6.6.2.1.

The protected check applies only to protected members of superclasses of the current class. protected members in other classes will be caught by the access checking done at resolution (5.4.4). There are four cases:

The predicate classesInOtherPkgWithProtectedMember(Class, MemberName, MemberDescriptor, MemberClassName, Chain, List) is true if List is the set of classes in Chain with name MemberClassName that are in a different run-time package than Class which have a protected member named MemberName with descriptor MemberDescriptor.

classesInOtherPkgWithProtectedMember(_, _, _, _, [], []).

classesInOtherPkgWithProtectedMember(Class, MemberName,
MemberDescriptor, MemberClassName,
[class(MemberClassName, L) Super | Tail],
[class(MemberClassName, L) Super | T]) :-

classClassName(Super, MemberClassName),
differentRuntimePackage(Class, class(MemberClassName, L) Super),
loadedClass(MemberClassName, L, Super),
isProtected(Super, MemberName, MemberDescriptor),
classesInOtherPkgWithProtectedMember(
Class, MemberName, MemberDescriptor, MemberClassName, Tail, T).

classesInOtherPkgWithProtectedMember(Class, MemberName,
MemberDescriptor, MemberClassName,
[class(MemberClassName, L) Super | Tail],
T) :-

classClassName(Super, MemberClassName),
differentRuntimePackage(Class, class(MemberClassName, L) Super),
loadedClass(MemberClassName, L, Super),
isNotProtected(Super, MemberName, MemberDescriptor),
classesInOtherPkgWithProtectedMember(
Class, MemberName, MemberDescriptor, MemberClassName, Tail, T).

classesInOtherPkgWithProtectedMember(Class, MemberName,
MemberDescriptor, MemberClassName,
[class(MemberClassName, L) Super | Tail],
T) :-

classClassName(Super, MemberClassName),
sameRuntimePackage(Class, class(MemberClassName, L) Super),
classesInOtherPkgWithProtectedMember(
Class, MemberName, MemberDescriptor, MemberClassName, Tail, T).

sameRuntimePackage(Class1, Class2) :-

classDefiningLoader(Class1, L),
classDefiningLoader(Class2, L),
samePackageName(Class1, Class2).

differentRuntimePackage(Class1, Class2) :-

classDefiningLoader(Class1, L1),
classDefiningLoader(Class2, L2),
L1 = L2.

differentRuntimePackage(Class1, Class2) :-

differentPackageName(Class1, Class2).

4.10.1.9 Type Checking Instructions

...

aaload

An aaload instruction is type safe iff one can validly replace types matching int and an array type with component type ComponentType where ComponentType is a subtype of Object, with ComponentType yielding the outgoing type state.

instructionIsTypeSafe(aaload, Environment, _Offset, StackFrame, NextStackFrame, ExceptionStackFrame) :-

nth1OperandStackIs(2, StackFrame, ArrayType),
arrayComponentType(ArrayType, ComponentType),
isBootstrapLoader(BL),
validTypeTransition(Environment,
[int, arrayOf(refclass('java/lang/Object', BL))],
ComponentType, StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).

The component type of an array of X is X. We define the component type of null to be null.

arrayComponentType(arrayOf(X), X).
arrayComponentType(null, null).

aastore

An aastore instruction is type safe iff one can validly pop types matching Object, int, and an array of Object off the incoming operand stack yielding the outgoing type state.

instructionIsTypeSafe(aastore, _Environment, _Offset, StackFrame, NextStackFrame, ExceptionStackFrame) :-

isBootstrapLoader(BL),
canPop(StackFrame,
[refclass('java/lang/Object', BL), int, arrayOf(refclass('java/lang/Object', BL))],
NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).

...

anewarray

An anewarray instruction with operand CP is type safe iff CP refers to a constant pool entry denoting either a class type or an array type, and one can legally replace a type matching int on the incoming operand stack with an array with component type given by CP, yielding the outgoing type state.

instructionIsTypeSafe(anewarray(CP), Environment, _Offset, StackFrame, NextStackFrame, ExceptionStackFrame) :-

(CP = class(_, _) ; CP = arrayOf(_)),
parseConstantClassType(CP, ComponentType),
validTypeTransition(Environment, [int], arrayOf(CP ComponentType), StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).

We don't need to assert that CP is a reference class type or array type (or, now, direct value class type). There are no other possibilities, assuming the bytecode is properly formatted (4.8, 4.9.1).

...

athrow

An athrow instruction is type safe iff the top of the operand stack matches Throwable.

instructionIsTypeSafe(athrow, _Environment, _Offset, StackFrame, afterGoto, ExceptionStackFrame) :-

isBootstrapLoader(BL),
canPop(StackFrame, [refclass('java/lang/Throwable', BL)], _PoppedStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).

...

checkcast

A checkcast instruction with operand CP is type safe iff CP refers to a constant pool entry denoting either a class or an array, and one can validly replace the type Object on top of the incoming operand stack with the type denoted by CP yielding the outgoing type state.

instructionIsTypeSafe(checkcast(CP), Environment, _Offset, StackFrame, NextStackFrame, ExceptionStackFrame) :-

(CP = class(_, _) ; CP = arrayOf(_)),
parseConstantClassType(CP, Type),
isBootstrapLoader(BL),
validTypeTransition(Environment, [refclass('java/lang/Object', BL)], CP Type, StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).

We don't need to assert that CP is not a direct value class type. That was already asserted by format checking (4.8, 4.9.1).

...

getfield

A getfield instruction with operand CP is type safe iff CP refers to a constant pool entry denoting a field whose declared type is FieldType, declared in a class FieldClass type FieldClassType, and one can validly replace a type matching FieldClassType with type FieldType on the incoming operand stack yielding the outgoing type state. FieldClass must not be an array type. protected fields are subject to additional checks (4.10.1.8).

instructionIsTypeSafe(getfield(CP), Environment, _Offset, StackFrame, NextStackFrame, ExceptionStackFrame) :-

CP = field(CC, FieldName, FieldDescriptor),
parseConstantClassType(CC, FieldClassType),
parseFieldDescriptor(FieldDescriptor, FieldType),
passesProtectedCheck(Environment, FieldClass FieldClassType, FieldName, FieldDescriptor, StackFrame),
validTypeTransition(Environment, [class(FieldClass) FieldClassType], FieldType, StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).

...

instanceof

An instanceof instruction with operand CP is type safe iff CP refers to a constant pool entry denoting either a class or an array, and one can validly replace the type Object on top of the incoming operand stack with type int yielding the outgoing type state.

instructionIsTypeSafe(instanceof(CP), Environment, _Offset, StackFrame, NextStackFrame, ExceptionStackFrame) :-

(CP = class(_, _) ; CP = arrayOf(_)),
isBootstrapLoader(BL),
validTypeTransition(Environment, [refclass('java/lang/Object', BL)], int, StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).

We don't need to assert that CP is not a direct value class type. That was already asserted by format checking (4.8, 4.9.1).

...

invokeinterface

An invokeinterface instruction is type safe iff all of the following are true:

instructionIsTypeSafe(invokeinterface(CP, Count, 0), Environment, _Offset, StackFrame, NextStackFrame, ExceptionStackFrame) :-

CP = imethod(CC, MethodName, Descriptor),
MethodName \= '<init>',
MethodName \= '<clinit>',
parseConstantClassType(CC, MethodIntfType),
parseMethodDescriptor(Descriptor, OperandArgList, ReturnType),
currentClassLoader(Environment, CurrentLoader),
reverse([class(MethodIntfName, CurrentLoader) MethodIntfType | OperandArgList], StackArgList),
canPop(StackFrame, StackArgList, TempFrame),
validTypeTransition(Environment, [], ReturnType, TempFrame, NextStackFrame),
countIsValid(Count, StackFrame, TempFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).

The Count operand of an invokeinterface instruction is valid if it equals the size of the arguments to the instruction. This is equal to the difference between the size of InputFrame and OutputFrame.

countIsValid(Count, InputFrame, OutputFrame) :-

_InputFrame = frame(_Locals1, OperandStack1, Flags1),
_OutputFrame = frame(_Locals2, OperandStack2, Flags2),
length(OperandStack1, Length1),
length(OperandStack2, Length2),
Count =:= Length1 - Length2.

invokespecial

An invokespecial instruction is type safe iff all of the following are true:

The rule for invokespecial of an <init> method is the sole motivation for passing back a distinct exception stack frame. The concern is that when initializing an object within its constructor, invokespecial can cause a superclass <init> method to be invoked, and that invocation could fail, leaving this uninitialized. This situation cannot be created using source code in the Java programming language, but can be created by programming in bytecode directly.

In this situation, the original frame holds an uninitialized object in local variable 0 and has flag flagThisUninit. Normal termination of invokespecial initializes the uninitialized object and turns off the flagThisUninit flag. But if the invocation of an <init> method throws an exception, the uninitialized object might be left in a partially initialized state, and needs to be made permanently unusable. This is represented by an exception frame containing the broken object (the new value of the local) and the flagThisUninit flag (the old flag). There is no way to get from an apparently-initialized object bearing the flagThisUninit flag to a properly initialized object, so the object is permanently unusable.

If not for this situation, the flags of the exception stack frame would always be the same as the flags of the input stack frame.

...

invokevirtual

An invokevirtual instruction is type safe iff all of the following are true:

instructionIsTypeSafe(invokevirtual(CP), Environment, _Offset, StackFrame, NextStackFrame, ExceptionStackFrame) :-

CP = method(CC, MethodName, Descriptor),
MethodName = '<init>',
MethodName = '<clinit>',
parseConstantClassType(CC, MethodClassType),
parseMethodDescriptor(Descriptor, OperandArgList, ReturnType),
reverse(OperandArgList, ArgList),
currentClassLoader(Environment, CurrentLoader),
reverse([class(MethodClassName, CurrentLoader) MethodClassType | OperandArgList], StackArgList),
validTypeTransition(Environment, StackArgList, ReturnType, StackFrame, NextStackFrame),
canPop(StackFrame, ArgList, PoppedFrame),
passesProtectedCheck(Environment, MethodClassType, MethodName, Descriptor, PoppedFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).

...

ldc, ldc_w, ldc2_w

An ldc instruction with operand CP is type safe iff CP refers to a constant pool entry denoting an entity of type Type, where Type is either int, float, String, Class, java.lang.invoke.MethodType, or java.lang.invoke.MethodHandle, and one can validly push Type onto the incoming operand stack yielding the outgoing type state.

instructionIsTypeSafe(ldc(CP), Environment, _Offset, StackFrame, NextStackFrame, ExceptionStackFrame) :-

functor(CP, Tag, _),
isBootstrapLoader(BL),
member([Tag, Type], [
[int, int],
[float, float],
[string, refclass('java/lang/String', BL)],
[classConst, refclass('java/lang/Class', BL)],
[methodTypeConst, refclass('java/lang/invoke/MethodType', BL)],
[methodHandleConst, refclass('java/lang/invoke/MethodHandle', BL)],
]),

validTypeTransition(Environment, [], Type, StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).

An ldc_w instruction is type safe iff the equivalent ldc instruction is type safe.

instructionHasEquivalentTypeRule(ldc_w(CP), ldc(CP)).

An ldc2_w instruction with operand CP is type safe iff CP refers to a constant pool entry denoting an entity of type Tag, where Tag is either long or double, and one can validly push Tag onto the incoming operand stack yielding the outgoing type state.

instructionIsTypeSafe(ldc2_w(CP), Environment, _Offset, StackFrame, NextStackFrame, ExceptionStackFrame) :-

functor(CP, Tag, _),
member(Tag, [long, double]),
validTypeTransition(Environment, [], Tag, StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).

...

multianewarray

A multianewarray instruction with operands CP and Dim is type safe iff CP refers to a constant pool entry denoting an array type whose dimension is greater or equal to Dim, Dim is strictly positive, and one can validly replace Dim int types on the incoming operand stack with the type denoted by CP yielding the outgoing type state.

instructionIsTypeSafe(multianewarray(CP, Dim), Environment, _Offset, StackFrame, NextStackFrame, ExceptionStackFrame) :-

parseConstantClassType(CP, ArrayType),
CP ArrayType = arrayOf(_),
arrayDimensions(CP ArrayType, Dimension),
Dimension >= Dim,
Dim > 0,
/* Make a list of Dim ints */
findall(int, between(1, Dim, _), IntList),
validTypeTransition(Environment, IntList, CP ArrayType, StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).

The dimensions of an array type whose component type is also an array type is one more than the dimensions of its component type.

classDimension(arrayOf(X), Dimension) :-

classDimension(X, Dimension1),
Dimension is Dimension1 + 1.

classDimension(_, Dimension) :-

Dimension = 0.

arrayDimensions(arrayOf(X), XDimensions + 1) :- arrayDimensions(X, XDimensions).
arrayDimensions(Type, 0) :- Type \= arrayOf(_).

Renamed this predicate, since the element type is not necessarily a class type. Also addressed a bug: the second rule previously would match array types as well as non-array types.

new

A new instruction with operand CP at offset Offset is type safe iff CP refers to a constant pool entry denoting a class type, the type uninitialized(Offset) does not appear in the incoming operand stack, and one can validly push uninitialized(Offset) onto the incoming operand stack and replace uninitialized(Offset) with top in the incoming local variables yielding the outgoing type state.

instructionIsTypeSafe(new(CP), Environment, Offset, StackFrame, NextStackFrame, ExceptionStackFrame) :-

StackFrame = frame(Locals, OperandStack, Flags),
CP = class(_, _),
NewItem = uninitialized(Offset),
notMember(NewItem, OperandStack),
substitute(NewItem, top, Locals, NewLocals),
validTypeTransition(Environment, [], NewItem, frame(NewLocals, OperandStack, Flags), NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).

The substitute predicate is defined in the rule for invokespecial.

We don't need to assert that CP is a reference class or interface type. That was already asserted by format checking (4.8, 4.9.1).

...

putfield

A putfield instruction with operand CP is type safe iff CP refers to a constant pool entry denoting a field whose declared type is FieldType, declared in a class FieldClass type FieldClassType, and one can validly pop types matching FieldType and FieldClass FieldClassType off the incoming operand stack yielding the outgoing type state.

instructionIsTypeSafe(putfield(CP), Environment, _Offset, StackFrame, NextStackFrame, ExceptionStackFrame) :-

CP = field(CC, FieldName, FieldDescriptor),
parseConstantClassType(CC, FieldClassType),
parseFieldDescriptor(FieldDescriptor, FieldType),
canPop(StackFrame, [FieldType], PoppedFrame),
passesProtectedCheck(Environment, FieldClassType, FieldName, FieldDescriptor, PoppedFrame),
currentClassLoader(Environment, CurrentLoader),
canPop(StackFrame, [FieldType, class(FieldClass, CurrentLoader) FieldClassType], NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).

...

vaload

A vaload instruction with operand CP is type safe iff CP refers to a type ComponentType and one can validly replace types matching int and an array of ComponentType on the incoming operand stack with ComponentType, yielding the outgoing type state.

instructionIsTypeSafe(vaload(CP), Environment, _Offset, StackFrame, NextStackFrame, ExceptionStackFrame) :-

parseConstantClassType(CP, ComponentType),
validTypeTransition(Environment, [int, arrayOf(ComponentType)], ComponentType, StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).

vastore

A vastore instruction with operand CP is type safe iff CP refers to a type ComponentType and one can validly pop types matching ComponentType, int, and array of ComponentType off the incoming operand stack yielding the outgoing type state.

instructionIsTypeSafe(vastore(CP), _Environment, _Offset, StackFrame, NextStackFrame, ExceptionStackFrame) :-

parseConstantClassType(CP, ComponentType),
canPop(StackFrame, [ComponentType, int, arrayOf(ComponentType)], NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).

vbox

A vbox instruction with operand CP is type safe iff CP refers to a type BoxedType and one can legally replace a type matching valueClass on the incoming operand stack with BoxedType, yielding the outgoing type state.

instructionIsTypeSafe(vbox(CP), Environment, _Offset, StackFrame, NextStackFrame, ExceptionStackFrame) :-

parseConstantClassType(CP, BoxedType),
validTypeTransition(Environment, [valueClass], BoxedType, StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).

vdefault

A vdefault instruction with operand CP is type safe iff CP refers to a type DirectValueClassType and one can validly push DirectValueClassType onto the incoming operand stack yielding the outgoing type state.

instructionIsTypeSafe(vdefault(CP), Environment, _Offset, StackFrame, NextStackFrame, ExceptionStackFrame) :-

parseConstantClassType(CP, DirectValueClassType),
validTypeTransition(Environment, [], DirectValueClassType, StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).

vload

A vload instruction with operand Index is type safe and yields an outgoing type state NextStackFrame, if a load instruction with operand Index and type valueClass is type safe and yields an outgoing type state NextStackFrame.

instructionIsTypeSafe(vload(Index), Environment, _Offset, StackFrame, NextStackFrame, ExceptionStackFrame) :-

loadIsTypeSafe(Environment, Index, valueClass, StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).

vreturn

A vreturn instruction is type safe iff the enclosing method has a declared return type, ReturnType, that is a direct value class type, and one can validly pop a type matching ReturnType off the incoming operand stack.

instructionIsTypeSafe(vreturn, Environment, _Offset, StackFrame, afterGoto, ExceptionStackFrame) :-

thisMethodReturnType(Environment, ReturnType),
isAssignable(ReturnType, valueClass),
canPop(StackFrame, [ReturnType], _PoppedStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).

vstore

A vstore instruction with operand Index is type safe and yields an outgoing type state NextStackFrame, if a store instruction with operand Index and type valueClass is type safe and yields an outgoing type state NextStackFrame.

instructionIsTypeSafe(astore(Index), Environment, _Offset, StackFrame, NextStackFrame, ExceptionStackFrame) :-

storeIsTypeSafe(Environment, Index, valueClass, StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).

vunbox

A vunbox instruction with operand CP is type safe iff CP refers to a type UnboxedType and one can legally replace a type matching reference on the incoming operand stack with BoxedType, yielding the outgoing type state.

instructionIsTypeSafe(vunbox(CP), Environment, _Offset, StackFrame, NextStackFrame, ExceptionStackFrame) :-

parseConstantClassType(CP, UnboxedType),
validTypeTransition(Environment, [reference], UnboxedType, StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).

vwithfield

A vwithfield instruction with operand CP is type safe iff CP refers to a constant pool entry denoting a field whose declared type is FieldType, declared in a direct value class type FieldClassType, and one can validly replace types matching FieldType and FieldClassType on the incoming operand stack with FieldClassType, yielding the outgoing type state.

instructionIsTypeSafe(vwithfield(CP), Environment, _Offset, StackFrame, NextStackFrame, ExceptionStackFrame) :-

CP = field(CC, FieldName, FieldDescriptor),
parseConstantClassType(CC, FieldClassType)
parseFieldDescriptor(FieldDescriptor, FieldType),
validTypeTransition(Environment, [FieldType, FieldClassType], FieldClassType, StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).

5.1 The Run-Time Constant Pool

The Java Virtual Machine maintains a per-type per-class constant pool (2.5.5), a run-time data structure that serves many of the purposes of the symbol table of a conventional programming language implementation.

The constant_pool table (4.4) in the binary representation of a class or interface is used to construct the run-time constant pool upon class or interface creation (5.3). All references in the run-time constant pool are initially symbolic. The symbolic references in the run-time constant pool are derived from structures in the binary representation of the class or interface as follows:

...

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 A class or interface C 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.

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 procedures to create class or interface C denoted by N:

References to loading of "array classes" are removed to clarify that types, such as array types, need not be loaded. Only classes and interfaces are loaded.

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.

...

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.

...

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.

...

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. Otherwise, the accessibility of the array class is public.

This section is unnecessary. There is no need for the notion of "loading" to extend to array types and other types.

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 = <N₁, L₁> makes a symbolic reference to a field or method of another class or interface D = <N₂, L₂>, 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 denote the same class or interface when loaded by L₁ and when loaded by L₂.

To ensure this, the Java Virtual Machine imposes loading constraints of the form N^L₁ = N^L₂ during preparation (5.4.2) and resolution (5.4.3).

The class or interface names mentioned by a descriptor (4.3) are as follows:

This definition of "mentions" allows us to eliminate boilerplate in a handful of other sections and gives us a single location to define how loading constraints are derived from new kinds of types.

To enforce these loading 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.

5.3.5 Deriving a Class from a class File Representation

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

...

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). Let L₁ be the defining loader of C. For each method m declared in C that overrides (5.4.5) a method declared in a superclass or superinterface <D, L₂>, the Java Virtual Machine imposes the following loading constraints: for each class or interface name N mentioned by the descriptor of m, the Java Virtual Machine imposes the loading constraint N^L₁ = N^L₂.

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

If Tr not an array type, let T0 be Tr; otherwise, let T0 be the element type (2.4) 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 (2.4) of Tfi.

Then Ti^L₁ =Ti^L₂ for i = 0 to n.

Furthermore, if C implements a method m declared in a superinterface of C, but C does not itself declare the method m, then let <D, L₂> be the superclass of C that declares the implementation of method m inherited by C. The Java Virtual Machine imposes the following constraints: For each class or interface name N mentioned by the descriptor of m, the Java Virtual Machine imposes the loading constraint N^L₂ = N^L₃.

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

If Tr not an array type, let T0 be Tr; otherwise, let T0 be the element type (2.4) 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 (2.4) of Tfi.

Then Ti^L₂ =Ti^L₃ for i = 0 to n.

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

5.4.3 Resolution

The Java Virtual Machine instructions anewarray, checkcast, getfield, getstatic, instanceof, invokedynamic, invokeinterface, invokespecial, invokestatic, invokevirtual, ldc, ldc_w, multianewarray, new, putfield, and putstatic, vaload, vastore, vbox, vdefault, vunbox, and vwithfield make symbolic references to the run-time constant pool. Execution of any of these instructions requires resolution of its symbolic reference.

Resolution is the process of dynamically determining concrete values from symbolic references in the run-time constant pool.

...

5.4.3.1 Class and Interface Type Resolution

A reference to a type (4.4.1) may take the form of a reference class or interface type, a direct value class type, or an array type.

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

  1. The defining class loader of D is used to create a class or interface, C, 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 type 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. The loaded class must not be a value class. If C has its ACC_VALUE flag set, type resolution throws an IncompatibleClassChangeError.

  4. Finally, access Access permissions to C are checked. If C is not accessible 5.4.4 to D, class or interface type resolution throws an IllegalAccessError.

    This condition can occur, for example, if C is a class that was originally declared to be public but was changed to be non-public after D was compiled.

  5. Finally, a representation, T, of the reference class or interface type of C is created.

To resolve an unresolved symbolic reference from D to a direct value class type T with class name N, the following steps are performed:

  1. The defining class loader of D is used to create a class or interface, C, denoted by N. 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 type resolution.

  2. The loaded class must be a value class. If C does not have its ACC_VALUE flag set, type resolution throws an IncompatibleClassChangeError.

  3. Access permissions to C are checked. If C is not accessible 5.4.4 to D, type resolution throws an IllegalAccessError.

  4. Finally, a representation, T, of the direct value class type of C is created.

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

  1. The component type, S, of the array is created by applying the rules of this section recursively.

    Any exception that can be thrown as a result of type resolution can occur when creating the component type.

  2. A representation, T, of an array type with component type S is created.

To resolve an unresolved symbolic reference from D to a primitive type, a representation of that type is created.

A CONSTANT_Class_info cannot be used to represent a primitive type. However, it is sometimes necessary to resolve a reference to a primitive type expressed as a descriptor (4.3.2) when resolving an array type, a method type (5.4.3.5), or a method handle (5.4.3.5).

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 type resolution 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, that symbolic reference to a type is invalid.

5.4.3.2 Field Resolution

To resolve an unresolved symbolic reference from D to a field in a class or interface C type T, the symbolic reference to C T 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 type can be thrown as a result of failure of field resolution. If the reference to C T can be successfully resolved, an exception relating to the failure of resolution of the field reference itself can be thrown.

Next, the class or interface named by T, C, is designated as the class or interface to search.

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

  1. If C 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.

  3. Otherwise, if C has a superclass S, field lookup is applied recursively to S.

  4. Otherwise, field lookup fails.

Then:

Given that the type of the referenced field is Tf, let T be Tf if Tf is not an array type, and let T be the element type (2.4) of Tf otherwise.

For each class or interface name N mentioned by the descriptor of the referenced field, the Java Virtual Machine must impose the loading constraint that N^L₁ = N^L₂ (5.3.4).

5.4.3.3 Method Resolution

To resolve an unresolved symbolic reference from D to a method in the reference class type T of a class C, the symbolic reference to C T 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 type can be thrown as a result of failure of method resolution. If the reference to C T can be successfully resolved, exceptions relating to the resolution of the method reference itself can be thrown.

...

The result of method resolution is determined by whether method lookup succeeds or fails:

...

5.4.3.4 Interface Method Resolution

To resolve an unresolved symbolic reference from D to an interface method in the interface type T of an interface C, the symbolic reference to C T 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 type can be thrown as a result of failure of method resolution. If the reference to C T can be successfully resolved, exceptions relating to the resolution of the interface method reference itself can be thrown.

...

The result of interface method resolution is determined by whether method lookup succeeds or fails:

...

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 the method descriptor (4.3.3).

Any exception that can be thrown as a result of failure of resolution of a class reference type 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 types 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 type in which the field or method is to be found.

...

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

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

In each step, any exception that can be thrown as a result of failure of resolution of a class or interface type or field or method reference can be thrown as a result of failure of method handle resolution.

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

...

5.5 Initialization

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

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 a class or interface type of 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 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, and its superclass has not yet been initialized, 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 ], 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.

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

  9. Next, execute the class or interface initialization method of C.

  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.

6.5 anewarray

Operation

Create a 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 item at that index must be a symbolic reference to a class, array, or interface type. The named class, array, or interface type is resolved (5.4.3.1), yielding the array component type.

If the referenced component type is a direct value class type, the named class is initialized (5.5) if that class has not already been initialized.

A new array with components of that type the referenced component type, of length count, is allocated from the garbage-collected heap, and a reference 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) of the component type (2.3.5, 2.4).

Linking Exceptions

During resolution of the symbolic reference to the class, array, or interface component 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.

Otherwise, if execution of this anewarray instruction causes initialization of a value class, anewarray may throw an Error as detailed in 5.5.

Notes

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

The newarray instruction is used to create an array with a primitive component type.

The anewarray opcode may only be used to create an array of a direct value class type in a version 54.1 class file (4.4.1).

6.5 getfield

Operation

Fetch a field from object a class instance

Format

getfield indexbyte1 indexbyte2

Forms

getfield = 180 (0xb4)

Operand Stack

..., objectref value
..., value 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 item at that 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 type in which the field is to be found. The referenced field is resolved (5.4.3.2).

The value, which must be of the referenced type, is popped from the operand stack. The value value of the referenced field in objectref value, result, is fetched and pushed onto the operand stack.

The type of objectref must not be an array type. If the field is protected, and it is a member of a superclass of the current class, and the field is not declared in the same run-time package (5.3) as the current class, then the class of objectref value must be either the current class or a subclass of the current class.

If the value has an array type, errors will occur (for example, verification may report that the array type may not be a subtype of the referenced type). But there's no need for a specific prohibition against array types.

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 value 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 (arraylength) is used instead.

The getfield opcode may only be used to access a field of a direct value class instance in a version 54.1 class file (4.4.2).

6.5 multianewarray

Operation

Create a 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 is the second, etc. All of the count values are popped off the operand stack.

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 item at that index must be a symbolic reference to a class, array, or interface type an array type. The named class, array, or interface type 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.

If the referenced array type's element type is a direct value class type, and if the number of dimensions of the array type is equal to dimensions, the named class is initialized (5.5) if that class has not already been initialized.

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.3.5, 2.4) for the element type of the array type that component type. A reference 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.

Run-time Exceptions

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

Otherwise, if execution of this multianewarray instruction causes initialization of a value class, multianewarray may throw an Error as detailed in 5.5.

Notes

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

The array class 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.

The multianewarray opcode may only be used to create an array with a direct value class element type in a version 54.1 class file (4.4.1).

6.5 new

...

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 item at the index must be a symbolic reference to a reference class or interface type. The named class or interface type is resolved (5.4.3.1) and should result in a reference 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 default initial values (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 (5.5) if it has not already been initialized.

...

6.5 vaload

Operation

Load a direct value class instance from an array

Format

vaload indexbyte1 indexbyte2

Forms

vaload = 205 (0xcd)

Operand Stack

..., arrayref, index →
..., 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 item at that index must be a symbolic reference to a direct value class type (4.4.1). The type is resolved (5.4.3.1).

The arrayref must be of type reference and must refer to an array whose components are of the referenced type. The index must be of type int.

Both arrayref and index are popped from the operand stack. The direct value class instance in the component of the array at index is retrieved and pushed onto the operand stack.

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.

Run-time Exceptions

Otherwise, if arrayref is null, vaload throws a NullPointerException.

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

Notes

The vaload opcode may only appear in version 54.1 class files (4.9.1).

6.5 vastore

Operation

Store a direct value class instance into an array

Format

vastore indexbyte1 indexbyte2

Forms

vastore = 206 (0xce)

Operand Stack

..., arrayref, index, 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 item at that index must be a symbolic reference to a direct value class type (4.4.1). The type is resolved (5.4.3.1).

The arrayref must be of type reference and must refer to an array whose components are of the referenced type. The index must be of type int. The value must be of the referenced type.

The arrayref, index, and value are popped from the operand stack. The value is stored as the component of the array indexed by index.

Run-time Exceptions

If arrayref is null, vastore throws a NullPointerException.

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

Notes

The vastore opcode may only appear in version 54.1 class files (4.9.1).

6.5 vbox

Operation

Convert a direct value class instance to a reference class instance

Format

vbox indexbyte1 indexbyte2

Forms

vbox = 216 (0xd6)

Operand Stack

..., value →
..., 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 item at that index must be a symbolic reference to a reference class or interface type (4.4.1). The type is resolved (5.4.3.1).

Let C be class or interface named by the referenced type. C must be a value-capable class (4.7.25). C is initialized (5.5) if that class has not already been initialized.

The value on the top of the operand stack must be a direct value class instance; the class of which value is an instance must have been derived from C (5.3). The value is popped from the operand stack and converted to an object stored in the garbage-collected heap that is an instance of C, with fields storing the same values as value. A reference to the object, objectref, is pushed onto the operand stack.

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 C is not a value-capable class, vbox throws an IncompatibleClassChangeError.

Run-time Exceptions

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

Otherwise, if the class of value was not derived from C, vbox throws an IncompatibleClassChangeError.

This check could be enforced at verification, but we prefer to keep the details of the mapping from value-capable classes to value classes out of the verification rules. Instead, verification ensures that the value has type valueClass, and then at run time we ensure that each input has the expected direct value class type.

Notes

The vbox opcode may only appear in version 54.1 class files (4.9.1).

A Java Virtual Machine implementation may choose to allocate new memory from the garbage-collected heap on each execution of a vbox instruction. Alternatively, a Java Virtual Machine implementation may choose to re-use an existing object without allocating any new memory.

The new instruction may also be used to create a reference to an instance of a value-capable class. In contrast to new, the result of vbox is already initialized and does not need to have an instance initialization method invoked.

6.5 vdefault

Operation

Push the default value of a direct value class type

Format

vdefault indexbyte1 indexbyte2

Forms

vdefault = 214 (0xd6)

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 item at that index must be a symbolic reference to a direct value class type (4.4.1). The type is resolved (5.4.3.1).

The named class is initialized (5.5) if that class has not already been initialized. The default value (2.3.5) of the direct value class type is pushed onto the operand stack.

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.

Run-time Exceptions

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

Notes

The vdefault opcode may only appear in version 54.1 class files (4.9.1).

A Java Virtual Machine implementation may choose to store the representation of the direct value in the operand stack, or may choose to allocate space for it in the heap (2.7).

6.5 vload

Operation

Load a direct value class instance from a local variable

Format

vload index

Forms

vload = 203 (0xcb)

Operand Stack

... →
..., value

Description

The index is an unsigned byte that must be an index into the local variable array of the current frame (2.6). The local variable at index must contain a direct value class instance. The value in the local variable at index is pushed onto the operand stack.

Notes

The vload opcode may only appear in version 54.1 class files (4.9.1).

The vload opcode can be used in conjunction with the wide instruction (wide) to access a local variable using a two-byte unsigned index.

6.5 vreturn

Operation

Return a direct value class instance from a method

Format

vreturn

Forms

vload = 210 (0xd2)

Operand Stack

..., value →
[empty]

Description

The return type of the current method must be a direct value class type, V. The value must be of type V.

If the current method is a synchronized method, the monitor entered or reentered on invocation of the method is updated and possibly exited as if by execution of a monitorexit instruction (monitorexit) in the current thread. If no exception is thrown, value is popped from the operand stack of the current frame (2.6) and pushed onto the operand stack of the frame of the invoker. Any other values on the operand stack of the current method are discarded.

The interpreter then returns control to the invoker of the method, reinstating the frame of the invoker.

Run-time Exceptions

If the Java Virtual Machine implementation does not enforce the rules on structured locking described in 2.11.10, then if the current method is a synchronized method and the current thread is not the owner of the monitor entered or reentered on invocation of the method, vreturn throws an IllegalMonitorStateException. This can happen, for example, if a synchronized method contains a monitorexit instruction, but no monitorenter instruction, on the object on which the method is synchronized.

Otherwise, if the Java Virtual Machine implementation enforces the rules on structured locking described in 2.11.10 and if the first of those rules is violated during invocation of the current method, then vreturn throws an IllegalMonitorStateException.

Notes

The vreturn opcode may only appear in version 54.1 class files (4.9.1).

6.5 vstore

Operation

Store a direct value class instance into a local variable

Format

vstore index

Forms

vstore = 204 (0xcc)

Operand Stack

..., value→
...

Description

The index is an unsigned byte that must be an index into the local variable array of the current frame (2.6). The value on the top of the operand stack must be a direct value class instance. It is popped from the operand stack, and the value of the local variable at index is set to value.

Notes

The vstore opcode may only appear in version 54.1 class files (4.9.1).

The vstore opcode can be used in conjunction with the wide instruction (wide) to access a local variable using a two-byte unsigned index.

6.5 vunbox

Operation

Convert a reference class instance to a direct value class instance

Format

vunbox indexbyte1 indexbyte2

Forms

vunbox = 217 (0xd7)

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 item at that index must be a symbolic reference to a direct value class type (4.4.1). The type is resolved (5.4.3.1).

Let V be the value class named by the referenced type.

The objectref on the top of the operand stack must be a a reference to an instance of the value-capable class from which V was derived (5.3). It is popped from the operand stack and converted to a direct value class instance of V, value, with fields storing the same values as objectref. The value is pushed onto the operand stack.

Linking Exceptions

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

Run-time Exceptions

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

Otherwise, if the objectref is not a reference to an instance of the value-capable class from which V was derived, vunbox throws an IncompatibleClassChangeError.

This check could be enforced at verification, but we prefer to keep the details of the mapping from value-capable classes to value classes out of the verification rules. Instead, verification ensures that the objectref has type reference, and then at run time we ensure that each input has the expected class type.

Notes

The vunbox opcode may only appear in version 54.1 class files (4.9.1).

A Java Virtual Machine implementation may choose to store the representation of the direct value in the operand stack, or may choose to allocate space for it in the heap (2.7).

6.5 vwithfield

Operation

Derive a direct value class instance from another, modifying a field

Format

vwithfield indexbyte1 indexbyte2

Forms

vwithfield = 215 (0xd7)

Operand Stack

..., value1, value2 →
..., result

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 item at that 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 direct value class type in which the field is to be found. The referenced field is resolved (5.4.3.2).

The type of value1 must be the direct value class type appearing in the field reference. The type of value2 must be compatible with the descriptor of the referenced field (4.3.2).

The values value1 and value2 are popped from the operand stack. value2 undergoes value set conversion (2.8.3), resulting in value2'. A new direct value class instance, result, is produced, with the referenced field storing value2', and all other fields storing their corresponding field values in value1. The result is pushed onto the operand stack.

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 class named by the referenced direct value class type is neither the current class nor a value class derived from the current class (5.3), the vwithfield instruction throws an IllegalAccessError.

Notes

The vwithfield opcode may only appear in version 54.1 class files (4.9.1).

A Java Virtual Machine implementation may choose to store the representation of the direct value in the operand stack, or may choose to allocate space for it in the heap (2.7).

The ability to create direct value class instances with the vwithfield instruction is limited. This gives the value-capable class some control over the valid set of direct value class instances, while still permitting read access to the instances' fields (getfield). Note, however, that the vdefault, newarray, and vunbox instructions may also be used to create direct value class instances, and these instructions do not enforce any access restrictions.

6.5 wide

Operation

Extend local variable index by additional bytes

Format 1

wide indexbyte1 indexbyte2

where is one of iload, fload, aload, vload, lload, dload, istore, fstore, astore, vstore, lstore, dstore, or ret

Format 2

wide iinc indexbyte1 indexbyte2 constbyte1 constbyte2

Forms

wide = 196 (0xc4)

Operand Stack

Same as modified instruction

Description

The wide instruction modifies the behavior of another instruction. It takes one of two formats, depending on the instruction being modified. The first form of the wide instruction modifies one of the instructions iload, fload, aload, vload, lload, dload, istore, fstore, astore, vstore, lstore, dstore, or ret (iload, fload, aload, vload, lload, dload, istore, fstore, astore, vstore, lstore, dstore, ret). The second form applies only to the iinc instruction (iinc).

In either case, the wide opcode itself is followed in the compiled code by the opcode of the instruction wide modifies. In either form, two unsigned bytes indexbyte1 and indexbyte2 follow the modified opcode and are assembled into a 16-bit unsigned index to a local variable in the current frame (2.6), where the value of the index is (indexbyte1 << 8) | indexbyte2. The calculated index must be an index into the local variable array of the current frame. Where the wide instruction modifies an lload, dload, lstore, or dstore instruction, the index following the calculated index (index + 1) must also be an index into the local variable array. In the second form, two immediate unsigned bytes constbyte1 and constbyte2 follow indexbyte1 and indexbyte2 in the code stream. Those bytes are also assembled into a signed 16-bit constant, where the constant is (constbyte1 << 8) | constbyte2.

The widened bytecode operates as normal, except for the use of the wider index and, in the case of the second form, the larger increment range.

Notes

Although we say that wide "modifies the behavior of another instruction," the wide instruction effectively treats the bytes constituting the modified instruction as operands, denaturing the embedded instruction in the process. In the case of a modified iinc instruction, one of the logical operands of the iinc is not even at the normal offset from the opcode. The embedded instruction must never be executed directly; its opcode must never be the target of any control transfer instruction.