Chapter 4. The class File Format
Table of Contents
- 4.1. The
ClassFileStructure - 4.2. Names
- 4.3. Descriptors
- 4.4. The Constant Pool
- 4.4.1. The
CONSTANT_Class_infoStructure - 4.4.2. The
CONSTANT_Fieldref_info,CONSTANT_Methodref_info, andCONSTANT_InterfaceMethodref_infoStructures - 4.4.3. The
CONSTANT_String_infoStructure - 4.4.4. The
CONSTANT_Integer_infoandCONSTANT_Float_infoStructures - 4.4.5. The
CONSTANT_Long_infoandCONSTANT_Double_infoStructures - 4.4.6. The
CONSTANT_NameAndType_infoStructure - 4.4.7. The
CONSTANT_Utf8_infoStructure - 4.4.8. The
CONSTANT_MethodHandle_infoStructure - 4.4.9. The
CONSTANT_MethodType_infoStructure - 4.4.10. The
CONSTANT_InvokeDynamic_infoStructure - 4.4.11. The
CONSTANT_Module_infoStructure - 4.4.12. The
CONSTANT_Package_infoStructure
- 4.4.1. The
- 4.5. Fields
- 4.6. Methods
- 4.7. Attributes
- 4.7.1. Defining and Naming New Attributes
- 4.7.2. The
ConstantValueAttribute - 4.7.3. The
CodeAttribute - 4.7.4. The
StackMapTableAttribute - 4.7.5. The
ExceptionsAttribute - 4.7.6. The
InnerClassesAttribute - 4.7.7. The
EnclosingMethodAttribute - 4.7.8. The
SyntheticAttribute - 4.7.9. The
SignatureAttribute - 4.7.10. The
SourceFileAttribute - 4.7.11. The
SourceDebugExtensionAttribute - 4.7.12. The
LineNumberTableAttribute - 4.7.13. The
LocalVariableTableAttribute - 4.7.14. The
LocalVariableTypeTableAttribute - 4.7.15. The
DeprecatedAttribute - 4.7.16. The
RuntimeVisibleAnnotationsAttribute - 4.7.17. The
RuntimeInvisibleAnnotationsAttribute - 4.7.18. The
RuntimeVisibleParameterAnnotationsAttribute - 4.7.19. The
RuntimeInvisibleParameterAnnotationsAttribute - 4.7.20. The
RuntimeVisibleTypeAnnotationsAttribute - 4.7.21. The
RuntimeInvisibleTypeAnnotationsAttribute - 4.7.22. The
AnnotationDefaultAttribute - 4.7.23. The
BootstrapMethodsAttribute - 4.7.24. The
MethodParametersAttribute - 4.7.25. The
ModuleAttribute - 4.7.26. The
ModulePackagesAttribute - 4.7.27. The
ModuleMainClassAttribute
- 4.8. Format Checking
- 4.9. Constraints on Java Virtual Machine Code
- 4.10. Verification of
classFiles - 4.10.1. Verification by Type Checking
- 4.10.1.1. Accessors for Java Virtual Machine Artifacts
- 4.10.1.2. Verification Type System
- 4.10.1.3. Instruction Representation
- 4.10.1.4. Stack Map Frames and Type Transitions
- 4.10.1.5. Type Checking Abstract and Native Methods
- 4.10.1.6. Type Checking Methods with Code
- 4.10.1.7. Type Checking Load and Store Instructions
- 4.10.1.8. Type Checking for
protectedMembers - 4.10.1.9. Type Checking Instructions
- aaload
- aastore
- aconst_null
- aload, aload_<n>
- anewarray
- areturn
- arraylength
- astore, astore_<n>
- athrow
- baload
- bastore
- bipush
- caload
- castore
- checkcast
- d2f, d2i, d2l
- dadd
- daload
- dastore
- dcmp<op>
- dconst_<d>
- ddiv
- dload, dload_<n>
- dmul
- dneg
- drem
- dreturn
- dstore, dstore_<n>
- dsub
- dup
- dup_x1
- dup_x2
- dup2
- dup2_x1
- dup2_x2
- f2d, f2i, f2l
- fadd
- faload
- fastore
- fcmp<op>
- fconst_<f>
- fdiv
- fload, fload_<n>
- fmul
- fneg
- frem
- freturn
- fstore, fstore_<n>
- fsub
- getfield
- getstatic
- goto, goto_w
- i2b, i2c, i2d, i2f, i2l, i2s
- iadd
- iaload
- iand
- iastore
- iconst_<i>
- idiv
- if_acmp<cond>
- if_icmp<cond>
- if<cond>
- ifnonnull, ifnull
- iinc
- iload, iload_<n>
- imul
- ineg
- instanceof
- invokedynamic
- invokeinterface
- invokespecial
- invokestatic
- invokevirtual
- ior, irem
- ireturn
- ishl, ishr, iushr
- istore, istore_<n>
- isub, ixor
- l2d, l2f, l2i
- ladd
- laload
- land
- lastore
- lcmp
- lconst_<l>
- ldc, ldc_w, ldc2_w
- ldiv
- lload, lload_<n>
- lmul
- lneg
- lookupswitch
- lor, lrem
- lreturn
- lshl, lshr, lushr
- lstore, lstore_<n>
- lsub, lxor
- monitorenter, monitorexit
- multianewarray
- new
- newarray
- nop
- pop, pop2
- putfield
- putstatic
- return
- saload
- sastore
- sipush
- swap
- tableswitch
- wide
- 4.10.2. Verification by Type Inference
- 4.11. Limitations of the Java Virtual Machine
This chapter describes the class file format of the Java Virtual Machine. Each class file contains the definition of a single class, interface, or module. Although a class, interface, or module need not have an external representation literally contained in a file (for instance, because the class is generated by a class loader), we will colloquially refer to any valid representation of a class, interface, or module as being in the class file format.
A class file consists of a stream of 8-bit bytes. 16-bit and 32-bit quantities are constructed by reading in two and four consecutive 8-bit bytes, respectively. Multibyte data items are always stored in big-endian order, where the high bytes come first. This chapter defines the data types u1, u2, and u4 to represent an unsigned one-, two-, or four-byte quantity, respectively.
In the Java SE Platform API, the class file format is supported by interfaces java.io.DataInput and java.io.DataOutput and classes such as java.io.DataInputStream and java.io.DataOutputStream. For example, values of the types u1, u2, and u4 may be read by methods such as readUnsignedByte, readUnsignedShort, and readInt of the interface java.io.DataInput.
This chapter presents the class file format using pseudostructures written in a C-like structure notation. To avoid confusion with the fields of classes and class instances, etc., the contents of the structures describing the class file format are referred to as items. Successive items are stored in the class file sequentially, without padding or alignment.
Tables, consisting of zero or more variable-sized items, are used in several class file structures. Although we use C-like array syntax to refer to table items, the fact that tables are streams of varying-sized structures means that it is not possible to translate a table index directly to a byte offset into the table.
Where we refer to a data structure as an array, it consists of zero or more contiguous fixed-sized items and can be indexed like an array.
Reference to an ASCII character in this chapter should be interpreted to mean the Unicode code point corresponding to the ASCII character.
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
magicitem supplies the magic number identifying theclassfile format; it has the value0xCAFEBABE. - minor_version, major_version
-
The values of the
minor_versionandmajor_versionitems are the minor and major version numbers of thisclassfile. Together, a major and a minor version number determine the version of theclassfile format. If aclassfile has major version number M and minor version number m, we denote the version of itsclassfile format as M.m. Thus,classfile format versions may be ordered lexicographically, for example, 1.5 < 2.0 < 2.1.A Java Virtual Machine implementation can support a
classfile 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.Oracle's Java Virtual Machine implementation in JDK release 1.0.2 supports
classfile format versions 45.0 through 45.3 inclusive. JDK releases 1.1.* supportclassfile format versions in the range 45.0 through 45.65535 inclusive. For k ≥ 2, JDK release 1.k supportsclassfile format versions in the range 45.0 through 44+k.0 inclusive. - constant_pool_count
-
The value of the
constant_pool_countitem is equal to the number of entries in theconstant_pooltable plus one. Aconstant_poolindex is considered valid if it is greater than zero and less thanconstant_pool_count, with the exception for constants of typelonganddoublenoted in §4.4.5. - constant_pool[]
-
The
constant_poolis a table of structures (§4.4) representing various string constants, class and interface names, field names, and other constants that are referred to within theClassFilestructure and its substructures. The format of eachconstant_pooltable entry is indicated by its first "tag" byte.The
constant_pooltable is indexed from 1 toconstant_pool_count- 1. - access_flags
-
The value of the
access_flagsitem 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_PUBLIC0x0001 Declared public; may be accessed from outside its package.ACC_FINAL0x0010 Declared final; no subclasses allowed.ACC_SUPER0x0020 Treat superclass methods specially when invoked by the invokespecial instruction. ACC_INTERFACE0x0200 Is an interface, not a class. ACC_ABSTRACT0x0400 Declared abstract; must not be instantiated.ACC_SYNTHETIC0x1000 Declared synthetic; not present in the source code. ACC_ANNOTATION0x2000 Declared as an annotation type. ACC_ENUM0x4000 Declared as an enumtype.ACC_MODULE0x8000 Is a module, not a class or interface.
The
ACC_MODULEflag indicates that thisclassfile defines a module, not a class or interface. If theACC_MODULEflag is set, then special rules apply to theclassfile which are given at the end of this section. If theACC_MODULEflag is not set, then the rules immediately below the current paragraph apply to theclassfile.An interface is distinguished by the
ACC_INTERFACEflag being set. If theACC_INTERFACEflag is not set, thisclassfile defines a class, not an interface or module.If the
ACC_INTERFACEflag is set, theACC_ABSTRACTflag must also be set, and theACC_FINAL,ACC_SUPER,ACC_ENUM, andACC_MODULEflags set must not be set.If the
ACC_INTERFACEflag is not set, any of the other flags in Table 4.1-A may be set exceptACC_ANNOTATIONandACC_MODULE. However, such aclassfile must not have both itsACC_FINALandACC_ABSTRACTflags set (JLS §8.1.1.2).The
ACC_SUPERflag 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 theACC_SUPERflag. In Java SE 8 and above, the Java Virtual Machine considers theACC_SUPERflag to be set in everyclassfile, regardless of the actual value of the flag in theclassfile and the version of theclassfile.The
ACC_SUPERflag 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 generatedaccess_flagsin which the flag now representingACC_SUPERhad no assigned meaning, and Oracle's Java Virtual Machine implementation ignored the flag if it was set.The
ACC_SYNTHETICflag indicates that this class or interface was generated by a compiler and does not appear in source code.An annotation type (JLS §9.6) must have its
ACC_ANNOTATIONflag set. If theACC_ANNOTATIONflag is set, theACC_INTERFACEflag must also be set.The
ACC_ENUMflag indicates that this class or its superclass is declared as an enumerated type (JLS §8.9).All bits of the
access_flagsitem not assigned in Table 4.1-A are reserved for future use. They should be set to zero in generatedclassfiles and should be ignored by Java Virtual Machine implementations. - this_class
-
The value of the
this_classitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Class_infostructure (§4.4.1) representing the class or interface defined by thisclassfile. - super_class
-
For a class, the value of the
super_classitem either must be zero or must be a valid index into theconstant_pooltable. If the value of thesuper_classitem is nonzero, theconstant_poolentry at that index must be aCONSTANT_Class_infostructure representing the direct superclass of the class defined by thisclassfile. Neither the direct superclass nor any of its superclasses may have theACC_FINALflag set in theaccess_flagsitem of itsClassFilestructure.If the value of the
super_classitem is zero, then thisclassfile must represent the classObject, the only class or interface without a direct superclass.For an interface, the value of the
super_classitem must always be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Class_infostructure representing the classObject. - interfaces_count
-
The value of the
interfaces_countitem gives the number of direct superinterfaces of this class or interface type. - interfaces[]
-
Each value in the
interfacesarray must be a valid index into theconstant_pooltable. Theconstant_poolentry at each value ofinterfaces[i], where 0 ≤ i <interfaces_count, must be aCONSTANT_Class_infostructure representing an interface that is a direct superinterface of this class or interface type, in the left-to-right order given in the source for the type. - fields_count
-
The value of the
fields_countitem gives the number offield_infostructures in thefieldstable. Thefield_infostructures represent all fields, both class variables and instance variables, declared by this class or interface type. - fields[]
-
Each value in the
fieldstable must be afield_infostructure (§4.5) giving a complete description of a field in this class or interface. Thefieldstable includes only those fields that are declared by this class or interface. It does not include items representing fields that are inherited from superclasses or superinterfaces. - methods_count
-
The value of the
methods_countitem gives the number ofmethod_infostructures in themethodstable. - methods[]
-
Each value in the
methodstable must be amethod_infostructure (§4.6) giving a complete description of a method in this class or interface. If neither of theACC_NATIVEandACC_ABSTRACTflags are set in theaccess_flagsitem of amethod_infostructure, the Java Virtual Machine instructions implementing the method are also supplied.The
method_infostructures represent all methods declared by this class or interface type, including instance methods, class methods, instance initialization methods (§2.9.1), and any class or interface initialization method (§2.9.2). Themethodstable does not include items representing methods that are inherited from superclasses or superinterfaces. - attributes_count
-
The value of the
attributes_countitem gives the number of attributes in theattributestable of this class. - attributes[]
-
Each value of the
attributestable must be anattribute_infostructure (§4.7).The attributes defined by this specification as appearing in the
attributestable of aClassFilestructure are listed in Table 4.7-C.The rules concerning attributes defined to appear in the
attributestable of aClassFilestructure are given in §4.7.The rules concerning non-predefined attributes in the
attributestable of aClassFilestructure are given in §4.7.1.
If the ACC_MODULE flag is set in the access_flags item, then no other flag in the access_flags item may be set, and the following rules apply to the rest of the ClassFile structure:
-
major_version,minor_version: ≥ 53.0 (i.e. Java SE 9 and above) -
super_class,interfaces_count,fields_count,methods_count: zero -
attributes: OneModuleattribute must be present. Except forModule,ModulePackages,ModuleMainClass,InnerClasses,SourceFile,SourceDebugExtension,RuntimeVisibleAnnotations, andRuntimeInvisibleAnnotations, none of the pre-defined attributes (§4.7) may appear.
Class and interface names that appear in class file structures are always represented in a fully qualified form known as binary names (JLS §13.1). Such names are always represented as CONSTANT_Utf8_info structures (§4.4.7) and thus may be drawn, where not further constrained, from the entire Unicode codespace. Class and interface names are referenced from those CONSTANT_NameAndType_info structures (§4.4.6) which have such names as part of their descriptor (§4.3), and from all CONSTANT_Class_info structures (§4.4.1).
For historical reasons, the syntax of binary names that appear in class file structures differs from the syntax of binary names documented in JLS §13.1. In this internal form, the ASCII periods (.) that normally separate the identifiers which make up the binary name are replaced by ASCII forward slashes (/). The identifiers themselves must be unqualified names (§4.2.2).
For example, the normal binary name of class Thread is java.lang.Thread. In the internal form used in descriptors in the class file format, a reference to the name of class Thread is implemented using a CONSTANT_Utf8_info structure representing the string java/lang/Thread.
Names of methods, fields, local variables, and formal parameters are stored as unqualified names. An unqualified name must contain at least one Unicode code point and must not contain any of the ASCII characters . ; [ / (that is, period or semicolon or left square bracket or forward slash).
Method names are further constrained so that, with the exception of the special method names <init> and <clinit> (§2.9), they must not contain the ASCII characters < or > (that is, left angle bracket or right angle bracket).
Note that a field name or interface method name may be <init> or <clinit>, but no method invocation instruction may reference <clinit> and only the invokespecial instruction (§invokespecial) may reference <init>.
Module names referenced from the Module attribute are stored in CONSTANT_Module_info structures in the constant pool (§4.4.11). A CONSTANT_Module_info structure wraps a CONSTANT_Utf8_info structure that denotes the module name. Module names are not encoded in "internal form" like class and interface names, that is, the ASCII periods (.) that separate the identifiers in a module name are not replaced by ASCII forward slashes (/).
Module names may be drawn from the entire Unicode codespace, subject to the following constraints:
-
A module name must not contain any code point in the range '
u0000' to 'u001F' inclusive. -
The ASCII backslash (
) is reserved for use as an escape character in module names. It must not appear in a module name unless it is followed by an ASCII backslash, an ASCII colon (:), or an ASCII at-sign (@). The ASCII character sequencemay be used to encode a backslash in a module name. -
The ASCII colon (
:) and at-sign (@) are reserved for future use in module names. They must not appear in module names unless they are escaped. The ASCII character sequences:and@may be used to encode a colon and an at-sign in a module name.
Package names referenced from the Module attribute are stored in CONSTANT_Package_info structures in the constant pool (§4.4.12). A CONSTANT_Package_info structure wraps a CONSTANT_Utf8_info structure that represents a package name encoded in internal form.
A descriptor is a string representing the type of a field or method. Descriptors are represented in the class file format using modified UTF-8 strings (§4.4.7) and thus may be drawn, where not further constrained, from the entire Unicode codespace.
Descriptors are specified using a grammar. The grammar is a set of productions that describe how sequences of characters can form syntactically correct descriptors of various kinds. Terminal symbols of the grammar are shown in fixed width font. Nonterminal symbols are shown in italic type. The definition of a nonterminal is introduced by the name of the nonterminal being defined, followed by a colon. One or more alternative definitions for the nonterminal then follow on succeeding lines.
The syntax {x} on the right-hand side of a production denotes zero or more occurrences of x.
The phrase (one of) on the right-hand side of a production signifies that each of the terminal symbols on the following line or lines is an alternative definition.
A field descriptor represents the type of a class, instance, or local variable.
The characters of BaseType, the L and ; of ObjectType, and the [ of ArrayType are all ASCII characters.
ClassName represents a binary class or interface name encoded in internal form (§4.2.1).
The interpretation of field descriptors as types is shown in Table 4.3-A.
A field descriptor representing an array type is valid only if it represents a type with 255 or fewer dimensions.
Table 4.3-A. Interpretation of field descriptors
| FieldType term | Type | Interpretation |
|---|---|---|
B |
byte |
signed byte |
C |
char |
Unicode character code point in the Basic Multilingual Plane, encoded with UTF-16 |
D |
double |
double-precision floating-point value |
F |
float |
single-precision floating-point value |
I |
int |
integer |
J |
long |
long integer |
L ClassName ; |
reference |
an instance of class ClassName |
S |
short |
signed short |
Z |
boolean |
true or false |
[ |
reference |
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.
A method descriptor contains zero or more parameter descriptors, representing the types of parameters that the method takes, and a return descriptor, representing the type of the value (if any) that the method returns.
The character V indicates that the method returns no value (its result is void).
The method descriptor for the method:
Object m(int i, double d, Thread t) {...}
is:
(IDLjava/lang/Thread;)Ljava/lang/Object;
Note that the internal forms of the binary names of Thread and Object are used.
A method descriptor is valid only if it represents method parameters with a total length of 255 or less, where that length includes the contribution for this in the case of instance or interface method invocations. The total length is calculated by summing the contributions of the individual parameters, where a parameter of type long or double contributes two units to the length and a parameter of any other type contributes one unit.
A method descriptor is the same whether the method it describes is a class method or an instance method. Although an instance method is passed this, a reference to the object on which the method is being invoked, in addition to its intended arguments, that fact is not reflected in the method descriptor. The reference to this is passed implicitly by the Java Virtual Machine instructions which invoke instance methods (§2.6.1, §4.11).
Java Virtual Machine instructions do not rely on the run-time layout of classes, interfaces, class instances, or arrays. Instead, instructions refer to symbolic information in the constant_pooltable.
All constant_pool table entries have the following general format:
cp_info {
u1 tag;
u1 info[];
}
Each entry in the constant_pool table must begin with a 1-byte tag indicating the type of constant denoted by the entry. The constant types and their corresponding tag values are listed inTable 4.4-A. Each constant type is accompanied by the first version of the class file format in which it was defined, and the corresponding version of the Java SE Platform. (For old class file versions, the JDK release is used instead of the Java SE Platform version.)
Each tag byte must be followed by two or more bytes giving information about the specific constant. The format of the additional information depends on the tag byte, that is, the content of the info array varies with the value of tag.
Table 4.4-A. Constant pool tags
| Constant Type | Value | class file | Java SE |
|---|---|---|---|
CONSTANT_Class |
7 | 45.3 | 1.0.2 |
CONSTANT_Fieldref |
9 | 45.3 | 1.0.2 |
CONSTANT_Methodref |
10 | 45.3 | 1.0.2 |
CONSTANT_InterfaceMethodref |
11 | 45.3 | 1.0.2 |
CONSTANT_String |
8 | 45.3 | 1.0.2 |
CONSTANT_Integer |
3 | 45.3 | 1.0.2 |
CONSTANT_Float |
4 | 45.3 | 1.0.2 |
CONSTANT_Long |
5 | 45.3 | 1.0.2 |
CONSTANT_Double |
6 | 45.3 | 1.0.2 |
CONSTANT_NameAndType |
12 | 45.3 | 1.0.2 |
CONSTANT_Utf8 |
1 | 45.3 | 1.0.2 |
CONSTANT_MethodHandle |
15 | 51.0 | 7 |
CONSTANT_MethodType |
16 | 51.0 | 7 |
CONSTANT_InvokeDynamic |
18 | 51.0 | 7 |
|
|
19 | 53.0 | 9 |
|
|
20 | 53.0 | 9 |
The CONSTANT_Class_info structure is used to represent a class or an interface:
CONSTANT_Class_info {
u1 tag;
u2 name_index;
}
The items of the CONSTANT_Class_info structure are as follows:
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_pooltable. 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;.
An array type descriptor is valid only if it represents 255 or fewer dimensions.
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
tagitem of aCONSTANT_Fieldref_infostructure has the valueCONSTANT_Fieldref(9).The
tagitem of aCONSTANT_Methodref_infostructure has the valueCONSTANT_Methodref(10).The
tagitem of aCONSTANT_InterfaceMethodref_infostructure has the valueCONSTANT_InterfaceMethodref(11). - class_index
-
The value of the
class_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Class_infostructure (§4.4.1) representing a class or interface type that has the field or method as a member.The
class_indexitem of aCONSTANT_Methodref_infostructure must be a class type, not an interface type.The
class_indexitem of aCONSTANT_InterfaceMethodref_infostructure must be an interface type.The
class_indexitem of aCONSTANT_Fieldref_infostructure may be either a class type or an interface type. - name_and_type_index
-
The value of the
name_and_type_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_NameAndType_infostructure (§4.4.6). Thisconstant_poolentry 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_infostructure begins with a '<' ('u003c'), then the name must be the special name<init>, representing an instance initialization method (§2.9.1). The return type of such a method must bevoid.
The CONSTANT_String_info structure is used to represent constant objects of the type String:
CONSTANT_String_info {
u1 tag;
u2 string_index;
}
The items of the CONSTANT_String_info structure are as follows:
- tag
- string_index
-
The value of the
string_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Utf8_infostructure (§4.4.7) representing the sequence of Unicode code points to which theStringobject is to be initialized.
The CONSTANT_Integer_info and CONSTANT_Float_info structures represent 4-byte numeric (int and float) constants:
CONSTANT_Integer_info {
u1 tag;
u4 bytes;
}
CONSTANT_Float_info {
u1 tag;
u4 bytes;
}
The items of these structures are as follows:
- tag
-
The
tagitem of theCONSTANT_Integer_infostructure has the valueCONSTANT_Integer(3).The
tagitem of theCONSTANT_Float_infostructure has the valueCONSTANT_Float(4). - bytes
-
The
bytesitem of theCONSTANT_Integer_infostructure represents the value of theintconstant. The bytes of the value are stored in big-endian (high byte first) order.The
bytesitem of theCONSTANT_Float_infostructure represents the value of thefloatconstant in IEEE 754 floating-point single format (§2.3.2). The bytes of the single format representation are stored in big-endian (high byte first) order.The value represented by the
CONSTANT_Float_infostructure is determined as follows. The bytes of the value are first converted into anintconstant bits. Then:-
If bits is
0x7f800000, thefloatvalue will be positive infinity. -
If bits is
0xff800000, thefloatvalue will be negative infinity. -
If bits is in the range
0x7f800001through0x7fffffffor in the range0xff800001through0xffffffff, thefloatvalue will be NaN. -
In all other cases, let
s,e, andmbe three values that might be computed from bits:int s = ((bits >> 31) == 0) ? 1 : -1; int e = ((bits >> 23) & 0xff); int m = (e == 0) ? (bits & 0x7fffff) << 1 : (bits & 0x7fffff) | 0x800000;
Then the
floatvalue equals the result of the mathematical expressions · m · 2e-150. -
The CONSTANT_Long_info and CONSTANT_Double_info represent 8-byte numeric (long and double) constants:
CONSTANT_Long_info {
u1 tag;
u4 high_bytes;
u4 low_bytes;
}
CONSTANT_Double_info {
u1 tag;
u4 high_bytes;
u4 low_bytes;
}
All 8-byte constants take up two entries in the constant_pool table of the class file. If a CONSTANT_Long_info or CONSTANT_Double_info structure is the item in the constant_pooltable at index n, then the next usable item in the pool is located at index n+2. The constant_pool index n+1 must be valid but is considered unusable.
In retrospect, making 8-byte constants take two constant pool entries was a poor choice.
The items of these structures are as follows:
- tag
-
The
tagitem of theCONSTANT_Long_infostructure has the valueCONSTANT_Long(5).The
tagitem of theCONSTANT_Double_infostructure has the valueCONSTANT_Double(6). - high_bytes, low_bytes
-
The unsigned
high_bytesandlow_bytesitems of theCONSTANT_Long_infostructure together represent the value of thelongconstant((long) high_bytes << 32) + low_byteswhere the bytes of each of
high_bytesandlow_bytesare stored in big-endian (high byte first) order.The
high_bytesandlow_bytesitems of theCONSTANT_Double_infostructure together represent thedoublevalue in IEEE 754 floating-point double format (§2.3.2). The bytes of each item are stored in big-endian (high byte first) order.The value represented by the
CONSTANT_Double_infostructure is determined as follows. Thehigh_bytesandlow_bytesitems are converted into thelongconstant bits, which is equal to((long) high_bytes << 32) + low_bytes-
If bits is
0x7ff0000000000000L, thedoublevalue will be positive infinity. -
If bits is
0xfff0000000000000L, thedoublevalue will be negative infinity. -
If bits is in the range
0x7ff0000000000001Lthrough0x7fffffffffffffffLor in the range0xfff0000000000001Lthrough0xffffffffffffffffL, the double value will be NaN. -
In all other cases, let
s,e, andmbe three values that might be computed from bits:int s = ((bits >> 63) == 0) ? 1 : -1; int e = (int)((bits >> 52) & 0x7ffL); long m = (e == 0) ? (bits & 0xfffffffffffffL) << 1 : (bits & 0xfffffffffffffL) | 0x10000000000000L;
Then the floating-point value equals the
doublevalue of the mathematical expressions · m · 2e-1075. -
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
- name_index
-
The value of the
name_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Utf8_infostructure (§4.4.7) representing either a valid unqualified name denoting a field or method (§4.2.2), or the special method name<init>(§2.9.1). - descriptor_index
-
The value of the
descriptor_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Utf8_infostructure (§4.4.7) representing a valid field descriptor or method descriptor (§4.3.2, §4.3.3).
The CONSTANT_Utf8_info structure is used to represent constant string values:
CONSTANT_Utf8_info {
u1 tag;
u2 length;
u1 bytes[length];
}
The items of the CONSTANT_Utf8_info structure are as follows:
String content is encoded in modified UTF-8. Modified UTF-8 strings are encoded so that code point sequences that contain only non-null ASCII characters can be represented using only 1 byte per code point, but all code points in the Unicode codespace can be represented. Modified UTF-8 strings are not null-terminated. The encoding is as follows:
-
Code points in the range '
u0001' to 'u007F' are represented by a single byte:
The 7 bits of data in the byte give the value of the code point represented.
-
The null code point ('
u0000') and code points in the range 'u0080' to 'u07FF' are represented by a pair of bytesxandy:
The two bytes represent the code point with the value:
((x & 0x1f) << 6) + (y & 0x3f) -
Code points in the range '
u0800' to 'uFFFF' are represented by 3 bytesx,y, andz:
The three bytes represent the code point with the value:
((x & 0xf) << 12) + ((y & 0x3f) << 6) + (z & 0x3f) -
Characters with code points above U+FFFF (so-called supplementary characters) are represented by separately encoding the two surrogate code units of their UTF-16 representation. Each of the surrogate code units is represented by three bytes. This means supplementary characters are represented by six bytes,
u,v,w,x,y, andz:
The six bytes represent the code point with the value:
0x10000 + ((v & 0x0f) << 16) + ((w & 0x3f) << 10) + ((y & 0x0f) << 6) + (z & 0x3f)
The bytes of multibyte characters are stored in the class file in big-endian (high byte first) order.
There are two differences between this format and the "standard" UTF-8 format. First, the null character (char)0 is encoded using the 2-byte format rather than the 1-byte format, so that modified UTF-8 strings never have embedded nulls. Second, only the 1-byte, 2-byte, and 3-byte formats of standard UTF-8 are used. The Java Virtual Machine does not recognize the four-byte format of standard UTF-8; it uses its own two-times-three-byte format instead.
For more information regarding the standard UTF-8 format, see Section 3.9 Unicode Encoding Forms of The Unicode Standard, Version 8.0.0.
The CONSTANT_MethodHandle_info structure is used to represent a method handle:
CONSTANT_MethodHandle_info {
u1 tag;
u1 reference_kind;
u2 reference_index;
}
The items of the CONSTANT_MethodHandle_info structure are the following:
- tag
- reference_kind
-
The value of the
reference_kinditem must be in the range 1 to 9. The value denotes the kind of this method handle, which characterizes its bytecode behavior (§5.4.3.5). - reference_index
-
The value of the
reference_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be as follows:-
If the value of the
reference_kinditem is 1 (REF_getField), 2 (REF_getStatic), 3 (REF_putField), or 4 (REF_putStatic), then theconstant_poolentry at that index must be aCONSTANT_Fieldref_info(§4.4.2) structure representing a field for which a method handle is to be created. -
If the value of the
reference_kinditem is 5 (REF_invokeVirtual) or 8 (REF_newInvokeSpecial), then theconstant_poolentry at that index must be aCONSTANT_Methodref_infostructure (§4.4.2) representing a class's method or constructor (§2.9.1) for which a method handle is to be created. -
If the value of the
reference_kinditem is 6 (REF_invokeStatic) or 7 (REF_invokeSpecial), then if theclassfile version number is less than 52.0, theconstant_poolentry at that index must be aCONSTANT_Methodref_infostructure representing a class's method for which a method handle is to be created; if theclassfile version number is 52.0 or above, theconstant_poolentry at that index must be either aCONSTANT_Methodref_infostructure or aCONSTANT_InterfaceMethodref_infostructure (§4.4.2) representing a class's or interface's method for which a method handle is to be created. -
If the value of the
reference_kinditem is 9 (REF_invokeInterface), then theconstant_poolentry at that index must be aCONSTANT_InterfaceMethodref_infostructure representing an interface's method for which a method handle is to be created.
If the value of the
reference_kinditem is 5 (REF_invokeVirtual), 6 (REF_invokeStatic), 7 (REF_invokeSpecial), or 9 (REF_invokeInterface), the name of the method represented by aCONSTANT_Methodref_infostructure or aCONSTANT_InterfaceMethodref_infostructure must not be<init>or<clinit>.If the value is 8 (
REF_newInvokeSpecial), the name of the method represented by aCONSTANT_Methodref_infostructure must be<init>. -
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:
The CONSTANT_InvokeDynamic_info structure is used by an invokedynamic instruction (§invokedynamic) to specify a bootstrap method, the dynamic invocation name, the argument and return types of the call, and optionally, a sequence of additional constants called static arguments to the bootstrap method.
CONSTANT_InvokeDynamic_info {
u1 tag;
u2 bootstrap_method_attr_index;
u2 name_and_type_index;
}
The items of the CONSTANT_InvokeDynamic_info structure are as follows:
- tag
- bootstrap_method_attr_index
-
The value of the
bootstrap_method_attr_indexitem must be a valid index into thebootstrap_methodsarray of the bootstrap method table (§4.7.23) of thisclassfile. - name_and_type_index
-
The value of the
name_and_type_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_NameAndType_infostructure (§4.4.6) representing a method name and method descriptor (§4.3.3).
The CONSTANT_Module_info structure is used to represent a module:
CONSTANT_Module_info {
u1 tag;
u2 name_index;
}
The items of the CONSTANT_Module_info structure are as follows:
- tag
- name_index
-
The value of the
name_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Utf8_infostructure representing a valid module name (§4.2.3).
A CONSTANT_Module_info structure is permitted only in the constant pool of a class file that declares a module, that is, a ClassFile structure where the access_flags item has the ACC_MODULE flag set. In all other class files, a CONSTANT_Module_info structure is illegal.
The CONSTANT_Package_info structure is used to represent a package exported or opened by a module:
CONSTANT_Package_info {
u1 tag;
u2 name_index;
}
The items of the CONSTANT_Package_info structure are as follows:
- tag
- name_index
-
The value of the
name_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Utf8_infostructure representing a valid package name encoded in internal form (§4.2.3).
A CONSTANT_Package_info structure is permitted only in the constant pool of a class file that declares a module, that is, a ClassFile structure where the access_flags item has the ACC_MODULE flag set. In all other class files, a CONSTANT_Package_info structure is illegal.
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_flagsitem 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.Table 4.5-A. Field access and property flags
Flag Name Value Interpretation ACC_PUBLIC0x0001 Declared public; may be accessed from outside its package.ACC_PRIVATE0x0002 Declared private; usable only within the defining class.ACC_PROTECTED0x0004 Declared protected; may be accessed within subclasses.ACC_STATIC0x0008 Declared static.ACC_FINAL0x0010 Declared final; never directly assigned to after object construction (JLS §17.5).ACC_VOLATILE0x0040 Declared volatile; cannot be cached.ACC_TRANSIENT0x0080 Declared transient; not written or read by a persistent object manager.ACC_SYNTHETIC0x1000 Declared synthetic; not present in the source code. ACC_ENUM0x4000 Declared as an element of an enum.
Fields of classes may set any of the flags in Table 4.5-A. However, each field of a class may have at most one of its
ACC_PUBLIC,ACC_PRIVATE, andACC_PROTECTEDflags set (JLS §8.3.1), and must not have both itsACC_FINALandACC_VOLATILEflags set (JLS §8.3.1.4).Fields of interfaces must have their
ACC_PUBLIC,ACC_STATIC, andACC_FINALflags set; they may have theirACC_SYNTHETICflag set and must not have any of the other flags in Table 4.5-A set (JLS §9.3).The
ACC_SYNTHETICflag indicates that this field was generated by a compiler and does not appear in source code.The
ACC_ENUMflag indicates that this field is used to hold an element of an enumerated type.All bits of the
access_flagsitem not assigned in Table 4.5-A are reserved for future use. They should be set to zero in generatedclassfiles and should be ignored by Java Virtual Machine implementations. - name_index
-
The value of the
name_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Utf8_infostructure (§4.4.7) which represents a valid unqualified name denoting a field (§4.2.2). - descriptor_index
-
The value of the
descriptor_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Utf8_infostructure (§4.4.7) which represents a valid field descriptor (§4.3.2). - attributes_count
-
The value of the
attributes_countitem indicates the number of additional attributes of this field. - attributes[]
-
Each value of the
attributestable must be anattribute_infostructure (§4.7).A field can have any number of optional attributes associated with it.
The attributes defined by this specification as appearing in the
attributestable of afield_infostructure are listed in Table 4.7-C.The rules concerning attributes defined to appear in the
attributestable of afield_infostructure are given in §4.7.The rules concerning non-predefined attributes in the
attributestable of afield_infostructure are given in §4.7.1.
Each method, including each instance initialization method (§2.9.1) and the class or interface initialization method (§2.9.2), 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_flagsitem 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.Table 4.6-A. Method access and property flags
Flag Name Value Interpretation ACC_PUBLIC0x0001 Declared public; may be accessed from outside its package.ACC_PRIVATE0x0002 Declared private; accessible only within the defining class.ACC_PROTECTED0x0004 Declared protected; may be accessed within subclasses.ACC_STATIC0x0008 Declared static.ACC_FINAL0x0010 Declared final; must not be overridden (§5.4.5).ACC_SYNCHRONIZED0x0020 Declared synchronized; invocation is wrapped by a monitor use.ACC_BRIDGE0x0040 A bridge method, generated by the compiler. ACC_VARARGS0x0080 Declared with variable number of arguments. ACC_NATIVE0x0100 Declared native; implemented in a language other than the Java programming language.ACC_ABSTRACT0x0400 Declared abstract; no implementation is provided.ACC_STRICT0x0800 Declared strictfp; floating-point mode is FP-strict.ACC_SYNTHETIC0x1000 Declared synthetic; not present in the source code.
Methods of classes may have any of the flags in Table 4.6-A set. However, each method of a class may have at most one of its
ACC_PUBLIC,ACC_PRIVATE, andACC_PROTECTEDflags set (JLS §8.4.3).Methods of interfaces may have any of the flags in Table 4.6-A set except
ACC_PROTECTED,ACC_FINAL,ACC_SYNCHRONIZED, andACC_NATIVE(JLS §9.4). In aclassfile whose version number is less than 52.0, each method of an interface must have itsACC_PUBLICandACC_ABSTRACTflags set; in aclassfile whose version number is 52.0 or above, each method of an interface must have exactly one of itsACC_PUBLICandACC_PRIVATEflags set.If a method of a class or interface has its
ACC_ABSTRACTflag set, it must not have any of itsACC_PRIVATE,ACC_STATIC,ACC_FINAL,ACC_SYNCHRONIZED,ACC_NATIVE, orACC_STRICTflags set.An instance initialization method (§2.9.1) may have at most one of its
ACC_PUBLIC,ACC_PRIVATE, andACC_PROTECTEDflags set, and may also have itsACC_VARARGS,ACC_STRICT, andACC_SYNTHETICflags set, but must not have any of the other flags in Table 4.6-A set.A class or interface initialization method (§2.9.2) is called implicitly by the Java Virtual Machine, whereupon the value of its
access_flagsitem is ignored except for the setting of theACC_STRICTflag. Because the value of itsaccess_flagsitem is irrelevant (except for theACC_STRICTflag), a class or interface initialization method is exempt from the preceding rules about legal combinations of flags.The
ACC_BRIDGEflag is used to indicate a bridge method generated by a compiler for the Java programming language.The
ACC_VARARGSflag indicates that this method takes a variable number of arguments at the source code level. A method declared to take a variable number of arguments must be compiled with theACC_VARARGSflag set to 1. All other methods must be compiled with theACC_VARARGSflag set to 0.The
ACC_SYNTHETICflag indicates that this method was generated by a compiler and does not appear in source code, unless it is one of the methods named in §4.7.8.All bits of the
access_flagsitem not assigned in Table 4.6-A are reserved for future use. They should be set to zero in generatedclassfiles and should be ignored by Java Virtual Machine implementations. - name_index
-
The value of the
name_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Utf8_infostructure (§4.4.7) representing either a valid unqualified name denoting a method (§4.2.2), or (if this method is in a class rather than an interface) the special method name<init>, or the special method name<clinit>. - descriptor_index
-
The value of the
descriptor_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Utf8_infostructure representing a valid method descriptor (§4.3.3). Furthermore:A future edition of this specification may require that the last parameter descriptor of the method descriptor is an array type if the
ACC_VARARGSflag is set in theaccess_flagsitem. - attributes_count
-
The value of the
attributes_countitem indicates the number of additional attributes of this method. - attributes[]
-
Each value of the
attributestable must be anattribute_infostructure (§4.7).A method can have any number of optional attributes associated with it.
The attributes defined by this specification as appearing in the
attributestable of amethod_infostructure are listed in Table 4.7-C.The rules concerning attributes defined to appear in the
attributestable of amethod_infostructure are given in §4.7.The rules concerning non-predefined attributes in the
attributestable of amethod_infostructure are given in §4.7.1.
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 item 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 aCONSTANT_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.
26 attributes are predefined by this specification. They are listed three times, for ease of navigation:
-
Table 4.7-A is ordered by the attributes' section numbers in this chapter. Each attribute is accompanied by the first version of the
classfile format in which it was defined, and the corresponding version of the Java SE Platform. (For oldclassfile versions, the JDK release is used instead of the Java SE Platform version.) -
Table 4.7-B is orderd by the first version of the
classfile format in which each attribute was defined. -
Table 4.7-C is ordered by the location in a
classfile where each attribute is defined to appear.
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:
-
Five attributes are critical to correct interpretation of the
classfile by the Java Virtual Machine:In a
classfile of version V, each of these attributes must be recognized and correctly read by an implementation of the Java Virtual Machine if the implementation recognizesclassfiles 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. -
Eight attributes are not critical to correct interpretation of the
classfile by the Java Virtual Machine, but are either critical to correct interpretation of theclassfile by the class libraries of the Java SE Platform, or are useful for tools (in which case the section that specifies an attribute describes it as "optional"):In a
classfile of version V, each of these attributes must be recognized and correctly read by an implementation of the Java Virtual Machine if the implementation recognizesclassfiles 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. -
Thirteen attributes are not critical to correct interpretation of the
classfile by the Java Virtual Machine, but contain metadata about theclassfile that is either exposed by the class libraries of the Java SE Platform, or made available by tools (in which case the section that specifies an attribute describes it as "optional"):An implementation of the Java Virtual Machine 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 |
|
|
§4.7.25 | 53.0 | 9 |
|
|
§4.7.26 | 53.0 | 9 |
|
|
§4.7.27 | 53.0 | 9 |
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 |
|
|
53.0 | 9 | §4.7.25 |
|
|
53.0 | 9 | §4.7.26 |
|
|
53.0 | 9 | §4.7.27 |
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 |
|
|
ClassFile |
53.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 |
Compilers are permitted to define and emit class files containing new attributes in the attributes tables of class file structures, field_info structures, method_info structures, and Codeattributes (§4.7.3). Java Virtual Machine implementations are permitted to recognize and use new attributes found in these attributes tables. However, any attribute not defined as part of this specification must not affect the semantics of the class file. Java Virtual Machine implementations are required to silently ignore attributes they do not recognize.
For instance, defining a new attribute to support vendor-specific debugging is permitted. Because Java Virtual Machine implementations are required to ignore attributes they do not recognize, class files intended for that particular Java Virtual Machine implementation will be usable by other implementations even if those implementations cannot make use of the additional debugging information that the class files contain.
Java Virtual Machine implementations are specifically prohibited from throwing an exception or otherwise refusing to use class files simply because of the presence of some new attribute. Of course, tools operating on class files may not run correctly if given class files that do not contain all the attributes they require.
Two attributes that are intended to be distinct, but that happen to use the same attribute name and are of the same length, will conflict on implementations that recognize either attribute. Attributes defined other than in this specification should have names chosen according to the package naming convention described in The Java Language Specification, Java SE 9 Edition (JLS §6.1).
Future versions of this specification may define additional attributes.
The ConstantValue attribute is a fixed-length attribute in the attributes table of a field_info structure (§4.5). A ConstantValue attribute represents the value of a constant expression (JLS §15.28), and is used as follows:
-
If the
ACC_STATICflag in theaccess_flagsitem of thefield_infostructure is set, then the field represented by thefield_infostructure is assigned the value represented by itsConstantValueattribute as part of the initialization of the class or interface declaring the field (§5.5). This occurs prior to the invocation of the class or interface initialization method of that class or interface (§2.9.2). -
Otherwise, the Java Virtual Machine must silently ignore the attribute.
There may be at most one ConstantValue attribute in the attributes table of a field_info structure.
The ConstantValue attribute has the following format:
ConstantValue_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 constantvalue_index;
}
The items of the ConstantValue_attribute structure are as follows:
- attribute_name_index
-
The value of the
attribute_name_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Utf8_infostructure (§4.4.7) representing the string "ConstantValue". - attribute_length
-
The value of the
attribute_lengthitem of aConstantValue_attributestructure must be two. - constantvalue_index
-
The value of the
constantvalue_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index gives the constant value represented by this attribute. Theconstant_poolentry must be of a type appropriate to the field, as specified in Table 4.7.2-A.
The Code attribute is a variable-length attribute in the attributes table of a method_info structure (§4.6). A Code attribute contains the Java Virtual Machine instructions and auxiliary information for a method, including an instance initialization method and a class or interface initialization method (§2.9.1, §2.9.2).
If the method is either native or abstract, and is not a class or interface initialization method, then its method_info structure must not have a Code attribute in its attributes table. Otherwise, its method_info structure must have exactly one Code attribute in its attributes table.
The Code attribute has the following format:
Code_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 max_stack;
u2 max_locals;
u4 code_length;
u1 code[code_length];
u2 exception_table_length;
{ u2 start_pc;
u2 end_pc;
u2 handler_pc;
u2 catch_type;
} exception_table[exception_table_length];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
The items of the Code_attribute structure are as follows:
- attribute_name_index
-
The value of the
attribute_name_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Utf8_infostructure (§4.4.7) representing the string "Code". - attribute_length
-
The value of the
attribute_lengthitem indicates the length of the attribute, excluding the initial six bytes. - max_stack
-
The value of the
max_stackitem gives the maximum depth of the operand stack of this method (§2.6.2) at any point during execution of the method. - max_locals
-
The value of the
max_localsitem gives the number of local variables in the local variable array allocated upon invocation of this method (§2.6.1), including the local variables used to pass parameters to the method on its invocation.The greatest local variable index for a value of type
longordoubleismax_locals - 2. The greatest local variable index for a value of any other type ismax_locals - 1. - code_length
-
The value of the
code_lengthitem gives the number of bytes in thecodearray for this method.The value of
code_lengthmust be greater than zero (as thecodearray must not be empty) and less than 65536. - code[]
-
The
codearray gives the actual bytes of Java Virtual Machine code that implement the method.When the
codearray is read into memory on a byte-addressable machine, if the first byte of the array is aligned on a 4-byte boundary, the tableswitch and lookupswitch 32-bit offsets will be 4-byte aligned. (Refer to the descriptions of those instructions for more information on the consequences ofcodearray alignment.)The detailed constraints on the contents of the
codearray are extensive and are given in a separate section (§4.9). - exception_table_length
-
The value of the
exception_table_lengthitem gives the number of entries in theexception_tabletable. - exception_table[]
-
Each entry in the
exception_tablearray describes one exception handler in thecodearray. The order of the handlers in theexception_tablearray is significant (§2.10).Each
exception_tableentry contains the following four items:- start_pc, end_pc
-
The values of the two items
start_pcandend_pcindicate the ranges in thecodearray at which the exception handler is active. The value ofstart_pcmust be a valid index into thecodearray of the opcode of an instruction. The value ofend_pceither must be a valid index into thecodearray of the opcode of an instruction or must be equal tocode_length, the length of thecodearray. The value ofstart_pcmust be less than the value ofend_pc.The
start_pcis inclusive andend_pcis exclusive; that is, the exception handler must be active while the program counter is within the interval [start_pc,end_pc).The fact that
end_pcis exclusive is a historical mistake in the design of the Java Virtual Machine: if the Java Virtual Machine code for a method is exactly 65535 bytes long and ends with an instruction that is 1 byte long, then that instruction cannot be protected by an exception handler. A compiler writer can work around this bug by limiting the maximum size of the generated Java Virtual Machine code for any method, instance initialization method, or static initializer (the size of any code array) to 65534 bytes. - handler_pc
-
The value of the
handler_pcitem indicates the start of the exception handler. The value of the item must be a valid index into thecodearray and must be the index of the opcode of an instruction. - catch_type
-
If the value of the
catch_typeitem is nonzero, it must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Class_infostructure (§4.4.1) representing a class of exceptions that this exception handler is designated to catch. The exception handler will be called only if the thrown exception is an instance of the given class or one of its subclasses.The verifier checks that the class is
Throwableor a subclass ofThrowable(§4.9.2).If the value of the
catch_typeitem is zero, this exception handler is called for all exceptions.This is used to implement
finally(§3.13).
- attributes_count
-
The value of the
attributes_countitem indicates the number of attributes of theCodeattribute. - attributes[]
-
Each value of the
attributestable must be anattribute_infostructure (§4.7).A
Codeattribute can have any number of optional attributes associated with it.The attributes defined by this specification as appearing in the
attributestable of aCodeattribute are listed in Table 4.7-C.The rules concerning attributes defined to appear in the
attributestable of aCodeattribute are given in §4.7.The rules concerning non-predefined attributes in the
attributestable of aCodeattribute are given in §4.7.1.
The StackMapTable attribute is a variable-length attribute in the attributes table of a Code attribute (§4.7.3). A StackMapTable attribute is used during the process of verification by type checking (§4.10.1).
There may be at most one StackMapTable attribute in the attributes table of a Code attribute.
In a class file whose version number is 50.0 or above, if a method's Code attribute does not have a StackMapTable attribute, it has an implicit stack map attribute (§4.10.1). This implicit stack map attribute is equivalent to a StackMapTable attribute with number_of_entries equal to zero.
The StackMapTable attribute has the following format:
StackMapTable_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 number_of_entries;
stack_map_frame entries[number_of_entries];
}
The items of the StackMapTable_attribute structure are as follows:
- attribute_name_index
-
The value of the
attribute_name_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Utf8_infostructure (§4.4.7) representing the string "StackMapTable". - attribute_length
-
The value of the
attribute_lengthitem indicates the length of the attribute, excluding the initial six bytes. - number_of_entries
-
The value of the
number_of_entriesitem gives the number ofstack_map_frameentries in theentriestable. - entries[]
-
Each entry in the
entriestable describes one stack map frame of the method. The order of the stack map frames in theentriestable is significant.
A stack map frame specifies (either explicitly or implicitly) the bytecode offset at which it applies, and the verification types of local variables and operand stack entries for that offset.
Each stack map frame described in the entries table relies on the previous frame for some of its semantics. The first stack map frame of a method is implicit, and computed from the method descriptor by the type checker (§4.10.1.6). The stack_map_frame structure at entries[0] therefore describes the second stack map frame of the method.
The bytecode offset at which a stack map frame applies is calculated by taking the value offset_delta specified in the frame (either explicitly or implicitly), and adding offset_delta + 1 to the bytecode offset of the previous frame, unless the previous frame is the initial frame of the method. In that case, the bytecode offset at which the stack map frame applies is the value offset_delta specified in the frame.
By using an offset delta rather than storing the actual bytecode offset, we ensure, by definition, that stack map frames are in the correctly sorted order. Furthermore, by consistently using the formula offset_delta + 1 for all explicit frames (as opposed to the implicit first frame), we guarantee the absence of duplicates.
We say that an instruction in the bytecode has a corresponding stack map frame if the instruction starts at offset i in the code array of a Code attribute, and the Code attribute has aStackMapTable attribute whose entries array contains a stack map frame that applies at bytecode offset i.
A verification type specifies the type of either one or two locations, where a location is either a single local variable or a single operand stack entry. A verification type is represented by a discriminated union, verification_type_info, that consists of a one-byte tag, indicating which item of the union is in use, followed by zero or more bytes, giving more information about the tag.
union verification_type_info {
Top_variable_info;
Integer_variable_info;
Float_variable_info;
Long_variable_info;
Double_variable_info;
Null_variable_info;
UninitializedThis_variable_info;
Object_variable_info;
Uninitialized_variable_info;
}
A verification type that specifies one location in the local variable array or in the operand stack is represented by the following items of the verification_type_info union:
-
The
Top_variable_infoitem indicates that the local variable has the verification typetop.Top_variable_info { u1 tag = ITEM_Top; /* 0 */ } -
The
Integer_variable_infoitem indicates that the location has the verification typeint.Integer_variable_info { u1 tag = ITEM_Integer; /* 1 */ } -
The
Float_variable_infoitem indicates that the location has the verification typefloat.Float_variable_info { u1 tag = ITEM_Float; /* 2 */ } -
The
Null_variable_infotype indicates that the location has the verification typenull.Null_variable_info { u1 tag = ITEM_Null; /* 5 */ } -
The
UninitializedThis_variable_infoitem indicates that the location has the verification typeuninitializedThis.UninitializedThis_variable_info { u1 tag = ITEM_UninitializedThis; /* 6 */ } -
The
Object_variable_infoitem indicates that the location has the verification type which is the class represented by theCONSTANT_Class_infostructure (§4.4.1) found in theconstant_pooltable at the index given bycpool_index.Object_variable_info { u1 tag = ITEM_Object; /* 7 */ u2 cpool_index; } -
The
Uninitialized_variable_infoitem indicates that the location has the verification typeuninitialized(Offset). TheOffsetitem indicates the offset, in thecodearray of theCodeattribute that contains thisStackMapTableattribute, of the new instruction (§new) that created the object being stored in the location.Uninitialized_variable_info { u1 tag = ITEM_Uninitialized; /* 8 */ u2 offset; }
A verification type that specifies two locations in the local variable array or in the operand stack is represented by the following items of the verification_type_info union:
-
The
Long_variable_infoitem indicates that the first of two locations has the verification typelong.Long_variable_info { u1 tag = ITEM_Long; /* 4 */ } -
The
Double_variable_infoitem indicates that the first of two locations has the verification typedouble.Double_variable_info { u1 tag = ITEM_Double; /* 3 */ } -
The
Long_variable_infoandDouble_variable_infoitems indicate the verification type of the second of two locations as follows:
A stack map frame is represented by a discriminated union, stack_map_frame, which consists of a one-byte tag, indicating which item of the union is in use, followed by zero or more bytes, giving more information about the tag.
union stack_map_frame {
same_frame;
same_locals_1_stack_item_frame;
same_locals_1_stack_item_frame_extended;
chop_frame;
same_frame_extended;
append_frame;
full_frame;
}
The tag indicates the frame type of the stack map frame:
-
The frame type
same_frameis represented by tags in the range [0-63]. This frame type indicates that the frame has exactly the same local variables as the previous frame and that the operand stack is empty. Theoffset_deltavalue for the frame is the value of the tag item,frame_type.same_frame { u1 frame_type = SAME; /* 0-63 */ } -
The frame type
same_locals_1_stack_item_frameis represented by tags in the range [64, 127]. This frame type indicates that the frame has exactly the same local variables as the previous frame and that the operand stack has one entry. Theoffset_deltavalue for the frame is given by the formulaframe_type - 64. The verification type of the one stack entry appears after the frame type.same_locals_1_stack_item_frame { u1 frame_type = SAME_LOCALS_1_STACK_ITEM; /* 64-127 */ verification_type_info stack[1]; } -
The frame type
same_locals_1_stack_item_frame_extendedis represented by the tag 247. This frame type indicates that the frame has exactly the same local variables as the previous frame and that the operand stack has one entry. Theoffset_deltavalue for the frame is given explicitly, unlike in the frame typesame_locals_1_stack_item_frame. The verification type of the one stack entry appears afteroffset_delta.same_locals_1_stack_item_frame_extended { u1 frame_type = SAME_LOCALS_1_STACK_ITEM_EXTENDED; /* 247 */ u2 offset_delta; verification_type_info stack[1]; } -
The frame type
chop_frameis represented by tags in the range [248-250]. This frame type indicates that the frame has the same local variables as the previous frame except that the last klocal variables are absent, and that the operand stack is empty. The value of k is given by the formula251 - frame_type. Theoffset_deltavalue for the frame is given explicitly.chop_frame { u1 frame_type = CHOP; /* 248-250 */ u2 offset_delta; }Assume the verification types of local variables in the previous frame are given by
locals, an array structured as in thefull_frameframe type. Iflocals[M-1]in the previous frame represented local variable X andlocals[M]represented local variable Y, then the effect of removing one local variable is thatlocals[M-1]in the new frame represents local variable X andlocals[M]is undefined.It is an error if k is larger than the number of local variables in
localsfor the previous frame, that is, if the number of local variables in the new frame would be less than zero. -
The frame type
same_frame_extendedis represented by the tag 251. This frame type indicates that the frame has exactly the same local variables as the previous frame and that the operand stack is empty. Theoffset_deltavalue for the frame is given explicitly, unlike in the frame typesame_frame.same_frame_extended { u1 frame_type = SAME_FRAME_EXTENDED; /* 251 */ u2 offset_delta; } -
The frame type
append_frameis represented by tags in the range [252-254]. This frame type indicates that the frame has the same locals as the previous frame except that k additional locals are defined, and that the operand stack is empty. The value of k is given by the formulaframe_type - 251. Theoffset_deltavalue for the frame is given explicitly.append_frame { u1 frame_type = APPEND; /* 252-254 */ u2 offset_delta; verification_type_info locals[frame_type - 251]; }The 0th entry in
localsrepresents the verification type of the first additional local variable. Iflocals[M]represents local variableN, then:-
locals[M+1]represents local variableN+1iflocals[M]is one ofTop_variable_info,Integer_variable_info,Float_variable_info,Null_variable_info,UninitializedThis_variable_info,Object_variable_info, orUninitialized_variable_info; and -
locals[M+1]represents local variableN+2iflocals[M]is eitherLong_variable_infoorDouble_variable_info.
It is an error if, for any index i,
locals[i]represents a local variable whose index is greater than the maximum number of local variables for the method. -
-
The frame type
full_frameis represented by the tag 255. Theoffset_deltavalue for the frame is given explicitly.full_frame { u1 frame_type = FULL_FRAME; /* 255 */ u2 offset_delta; u2 number_of_locals; verification_type_info locals[number_of_locals]; u2 number_of_stack_items; verification_type_info stack[number_of_stack_items]; }The 0th entry in
localsrepresents the verification type of local variable 0. Iflocals[M]represents local variableN, then:-
locals[M+1]represents local variableN+1iflocals[M]is one ofTop_variable_info,Integer_variable_info,Float_variable_info,Null_variable_info,UninitializedThis_variable_info,Object_variable_info, orUninitialized_variable_info; and -
locals[M+1]represents local variableN+2iflocals[M]is eitherLong_variable_infoorDouble_variable_info.
It is an error if, for any index i,
locals[i]represents a local variable whose index is greater than the maximum number of local variables for the method.The 0th entry in
stackrepresents the verification type of the bottom of the operand stack, and subsequent entries instackrepresent the verification types of stack entries closer to the top of the operand stack. We refer to the bottom of the operand stack as stack entry 0, and to subsequent entries of the operand stack as stack entry 1, 2, etc. Ifstack[M]represents stack entryN, then:-
stack[M+1]represents stack entryN+1ifstack[M]is one ofTop_variable_info,Integer_variable_info,Float_variable_info,Null_variable_info,UninitializedThis_variable_info,Object_variable_info, orUninitialized_variable_info; and -
stack[M+1]represents stack entryN+2ifstack[M]is eitherLong_variable_infoorDouble_variable_info.
It is an error if, for any index i,
stack[i]represents a stack entry whose index is greater than the maximum operand stack size for the method. -
The Exceptions attribute is a variable-length attribute in the attributes table of a method_info structure (§4.6). The Exceptions attribute indicates which checked exceptions a method may throw.
There may be at most one Exceptions attribute in the attributes table of a method_info structure.
The Exceptions attribute has the following format:
Exceptions_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 number_of_exceptions;
u2 exception_index_table[number_of_exceptions];
}
The items of the Exceptions_attribute structure are as follows:
- attribute_name_index
-
The value of the
attribute_name_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be theCONSTANT_Utf8_infostructure (§4.4.7) representing the string "Exceptions". - attribute_length
-
The value of the
attribute_lengthitem indicates the attribute length, excluding the initial six bytes. - number_of_exceptions
-
The value of the
number_of_exceptionsitem indicates the number of entries in theexception_index_table. - exception_index_table[]
-
Each value in the
exception_index_tablearray must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Class_infostructure (§4.4.1) representing a class type that this method is declared to throw.
A method should throw an exception only if at least one of the following three criteria is met:
-
The exception is an instance of
RuntimeExceptionor one of its subclasses. -
The exception is an instance of
Erroror one of its subclasses. -
The exception is an instance of one of the exception classes specified in the
exception_index_tablejust described, or one of their subclasses.
These requirements are not enforced in the Java Virtual Machine; they are enforced only at compile time.
The InnerClasses attribute is a variable-length attribute in the attributes table of a ClassFile structure (§4.1).
If the constant pool of a class or interface C contains at least one CONSTANT_Class_info entry (§4.4.1) which represents a class or interface that is not a member of a package, then there must be exactly one InnerClasses attribute in the attributes table of the ClassFile structure for C.
The InnerClasses attribute has the following format:
InnerClasses_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 number_of_classes;
{ u2 inner_class_info_index;
u2 outer_class_info_index;
u2 inner_name_index;
u2 inner_class_access_flags;
} classes[number_of_classes];
}
The items of the InnerClasses_attribute structure are as follows:
- attribute_name_index
-
The value of the
attribute_name_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Utf8_infostructure (§4.4.7) representing the string "InnerClasses". - attribute_length
-
The value of the
attribute_lengthitem indicates the length of the attribute, excluding the initial six bytes. - number_of_classes
-
The value of the
number_of_classesitem indicates the number of entries in theclassesarray. - classes[]
-
Every
CONSTANT_Class_infoentry in theconstant_pooltable which represents a class or interface C that is not a package member must have exactly one corresponding entry in theclassesarray.If a class or interface has members that are classes or interfaces, its
constant_pooltable (and hence itsInnerClassesattribute) must refer to each such member (JLS §13.1), even if that member is not otherwise mentioned by the class.In addition, the
constant_pooltable of every nested class and nested interface must refer to its enclosing class, so altogether, every nested class and nested interface will haveInnerClassesinformation for each enclosing class and for each of its own nested classes and interfaces.Each entry in the
classesarray contains the following four items:- inner_class_info_index
-
The value of the
inner_class_info_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Class_infostructure representing C. - outer_class_info_index
-
If C is not a member of a class or an interface - that is, if C is a top-level class or interface (JLS §7.6) or a local class (JLS §14.3) or an anonymous class (JLS §15.9.5) - then the value of the
outer_class_info_indexitem must be zero.Otherwise, the value of the
outer_class_info_indexitem must be a valid index into theconstant_pooltable, and the entry at that index must be aCONSTANT_Class_infostructure representing the class or interface of which C is a member. The value of theouter_class_info_indexitem must not equal the the value of theinner_class_info_indexitem. - inner_name_index
-
If C is anonymous (JLS §15.9.5), the value of the
inner_name_indexitem must be zero.Otherwise, the value of the
inner_name_indexitem must be a valid index into theconstant_pooltable, and the entry at that index must be aCONSTANT_Utf8_infostructure that represents the original simple name of C, as given in the source code from which thisclassfile was compiled. - inner_class_access_flags
-
The value of the
inner_class_access_flagsitem is a mask of flags used to denote access permissions to and properties of class or interface C as declared in the source code from which thisclassfile was compiled. It is used by a compiler to recover the original information when source code is not available. The flags are specified in Table 4.7.6-A.Table 4.7.6-A. Nested class access and property flags
Flag Name Value Interpretation ACC_PUBLIC0x0001 Marked or implicitly publicin source.ACC_PRIVATE0x0002 Marked privatein source.ACC_PROTECTED0x0004 Marked protectedin source.ACC_STATIC0x0008 Marked or implicitly staticin source.ACC_FINAL0x0010 Marked or implicitly finalin source.ACC_INTERFACE0x0200 Was an interfacein source.ACC_ABSTRACT0x0400 Marked or implicitly abstractin source.ACC_SYNTHETIC0x1000 Declared synthetic; not present in the source code. ACC_ANNOTATION0x2000 Declared as an annotation type. ACC_ENUM0x4000 Declared as an enumtype.
All bits of the
inner_class_access_flagsitem not assigned in Table 4.7.6-A are reserved for future use. They should be set to zero in generatedclassfiles and should be ignored by Java Virtual Machine implementations.
If a
classfile has a version number that is 51.0 or above, and has anInnerClassesattribute in itsattributestable, then for all entries in theclassesarray of theInnerClassesattribute, the value of theouter_class_info_indexitem must be zero if the value of theinner_name_indexitem is zero.
Oracle's Java Virtual Machine implementation does not check the consistency of an InnerClasses attribute against a class file representing a class or interface referenced by the attribute.
The EnclosingMethod attribute is a fixed-length attribute in the attributes table of a ClassFile structure (§4.1). A class must have an EnclosingMethod attribute if and only if it represents a local class or an anonymous class (JLS §14.3, JLS §15.9.5).
There may be at most one EnclosingMethod attribute in the attributes table of a ClassFile structure.
The EnclosingMethod attribute has the following format:
EnclosingMethod_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 class_index;
u2 method_index;
}
The items of the EnclosingMethod_attribute structure are as follows:
- attribute_name_index
-
The value of the
attribute_name_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Utf8_infostructure (§4.4.7) representing the string "EnclosingMethod". - attribute_length
- class_index
-
The value of the
class_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Class_infostructure (§4.4.1) representing the innermost class that encloses the declaration of the current class. - method_index
-
If the current class is not immediately enclosed by a method or constructor, then the value of the
method_indexitem must be zero.In particular,
method_indexmust be zero if the current class was immediately enclosed in source code by an instance initializer, static initializer, instance variable initializer, or class variable initializer. (The first two concern both local classes and anonymous classes, while the last two concern anonymous classes declared on the right hand side of a field assignment.)Otherwise, the value of the
method_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_NameAndType_infostructure (§4.4.6) representing the name and type of a method in the class referenced by theclass_indexattribute above.It is the responsibility of a Java compiler to ensure that the method identified via the
method_indexis indeed the closest lexically enclosing method of the class that contains thisEnclosingMethodattribute.
The Synthetic attribute is a fixed-length attribute in the attributes table of a ClassFile, field_info, or method_info structure (§4.1, §4.5, §4.6). A class member that does not appear in the source code must be marked using a Synthetic attribute, or else it must have its ACC_SYNTHETIC flag set. The only exceptions to this requirement are compiler-generated methods which are not considered implementation artifacts, namely the instance initialization method representing a default constructor of the Java programming language (§2.9.1), the class or interface initialization method (§2.9.2), and the Enum.values() and Enum.valueOf() methods.
The Synthetic attribute was introduced in JDK 1.1 to support nested classes and interfaces.
The Synthetic attribute has the following format:
Synthetic_attribute {
u2 attribute_name_index;
u4 attribute_length;
}
The items of the Synthetic_attribute structure are as follows:
- attribute_name_index
-
The value of the
attribute_name_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Utf8_infostructure (§4.4.7) representing the string "Synthetic". - attribute_length
The Signature attribute is a fixed-length attribute in the attributes table of a ClassFile, field_info, or method_info structure (§4.1, §4.5, §4.6). A Signature attribute records a signature (§4.7.9.1) for a class, interface, constructor, method, or field whose declaration in the Java programming language uses type variables or parameterized types. See The Java Language Specification, Java SE 9 Edition for details about these constructs.
There may be at most one Signature attribute in the attributes table of a ClassFile, field_info, or method_info structure.
The Signature attribute has the following format:
Signature_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 signature_index;
}
The items of the Signature_attribute structure are as follows:
- attribute_name_index
-
The value of the
attribute_name_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Utf8_infostructure (§4.4.7) representing the string "Signature". - attribute_length
-
The value of the
attribute_lengthitem of aSignature_attributestructure must be two. - signature_index
-
The value of the
signature_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Utf8_infostructure (§4.4.7) representing a class signature if thisSignatureattribute is an attribute of aClassFilestructure; a method signature if thisSignatureattribute is an attribute of amethod_infostructure; or a field signature otherwise.
Oracle's Java Virtual Machine implementation does not check the well-formedness of Signature attributes during class loading or linking. Instead, Signature attributes are checked by methods of the Java SE Platform class libraries which expose generic signatures of classes, interfaces, constructors, methods, and fields. Examples include getGenericSuperclass in Class and toGenericString in java.lang.reflect.Executable.
Signatures encode declarations written in the Java programming language that use types outside the type system of the Java Virtual Machine. They support reflection and debugging, as well as compilation when only class files are available.
A Java compiler must emit a signature for any class, interface, constructor, method, or field whose declaration uses type variables or parameterized types. Specifically, a Java compiler must emit:
-
A class signature for any class or interface declaration which is either generic, or has a parameterized type as a superclass or superinterface, or both.
-
A method signature for any method or constructor declaration which is either generic, or has a type variable or parameterized type as the return type or a formal parameter type, or has a type variable in a
throwsclause, or any combination thereof.If the
throwsclause of a method or constructor declaration does not involve type variables, then a compiler may treat the declaration as having nothrowsclause for the purpose of emitting a method signature. -
A field signature for any field, formal parameter, or local variable declaration whose type uses a type variable or a parameterized type.
Signatures are specified using a grammar which follows the notation of §4.3.1. In addition to that notation:
-
The syntax [x] on the right-hand side of a production denotes zero or one occurrences of x. That is, x is an optional symbol. The alternative which contains the optional symbol actually defines two alternatives: one that omits the optional symbol and one that includes it.
-
A very long right-hand side may be continued on a second line by clearly indenting the second line.
The grammar includes the terminal symbol Identifier to denote the name of a type, field, method, formal parameter, local variable, or type variable, as generated by a Java compiler. Such a name must not contain any of the ASCII characters . ; [ / < > : (that is, the characters forbidden in method names (§4.2.2) and also colon) but may contain characters that must not appear in an identifier in the Java programming language (JLS §3.8).
Signatures rely on a hierarchy of nonterminals known as type signatures:
-
A Java type signature represents either a reference type or a primitive type of the Java programming language.
The following production from §4.3.2 is repeated here for convenience:
-
A reference type signature represents a reference type of the Java programming language, that is, a class or interface type, a type variable, or an array type.
A class type signature represents a (possibly parameterized) class or interface type. A class type signature must be formulated such that it can be reliably mapped to the binary name of the class it denotes by erasing any type arguments and converting each
.character to a$character.A type variable signature represents a type variable.
An array type signature represents one dimension of an array type.
A class signature encodes type information about a (possibly generic) class declaration. It describes any type parameters of the class, and lists its (possibly parameterized) direct superclass and direct superinterfaces, if any. A type parameter is described by its name, followed by any class bound and interface bounds.
A method signature encodes type information about a (possibly generic) method declaration. It describes any type parameters of the method; the (possibly parameterized) types of any formal parameters; the (possibly parameterized) return type, if any; and the types of any exceptions declared in the method's throws clause.
The following production from §4.3.3 is repeated here for convenience:
A method signature encoded by the Signature attribute may not correspond exactly to the method descriptor in the method_info structure (§4.3.3). In particular, there is no assurance that the number of formal parameter types in the method signature is the same as the number of parameter descriptors in the method descriptor. The numbers are the same for most methods, but certain constructors in the Java programming language have an implicitly declared parameter which a compiler represents with a parameter descriptor but may omit from the method signature. See the note in §4.7.18 for a similar situation involving parameter annotations.
A field signature encodes the (possibly parameterized) type of a field, formal parameter, or local variable declaration.
The SourceFile attribute is an optional fixed-length attribute in the attributes table of a ClassFile structure (§4.1).
There may be at most one SourceFile attribute in the attributes table of a ClassFile structure.
The SourceFile attribute has the following format:
SourceFile_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 sourcefile_index;
}
The items of the SourceFile_attribute structure are as follows:
- attribute_name_index
-
The value of the
attribute_name_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Utf8_infostructure (§4.4.7) representing the string "SourceFile". - attribute_length
-
The value of the
attribute_lengthitem of aSourceFile_attributestructure must be two. - sourcefile_index
-
The value of the
sourcefile_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Utf8_infostructure representing a string.The string referenced by the
sourcefile_indexitem will be interpreted as indicating the name of the source file from which thisclassfile was compiled. It will not be interpreted as indicating the name of a directory containing the file or an absolute path name for the file; such platform-specific additional information must be supplied by the run-time interpreter or development tool at the time the file name is actually used.
The SourceDebugExtension attribute is an optional attribute in the attributes table of a ClassFile structure (§4.1).
There may be at most one SourceDebugExtension attribute in the attributes table of a ClassFile structure.
The SourceDebugExtension attribute has the following format:
SourceDebugExtension_attribute {
u2 attribute_name_index;
u4 attribute_length;
u1 debug_extension[attribute_length];
}
The items of the SourceDebugExtension_attribute structure are as follows:
- attribute_name_index
-
The value of the
attribute_name_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Utf8_infostructure (§4.4.7) representing the string "SourceDebugExtension". - attribute_length
-
The value of the
attribute_lengthitem indicates the length of the attribute, excluding the initial six bytes. - debug_extension[]
-
The
debug_extensionarray holds extended debugging information which has no semantic effect on the Java Virtual Machine. The information is represented using a modified UTF-8 string (§4.4.7) with no terminating zero byte.Note that the
debug_extensionarray may denote a string longer than that which can be represented with an instance of classString.
The LineNumberTable attribute is an optional variable-length attribute in the attributes table of a Code attribute (§4.7.3). It may be used by debuggers to determine which part of the codearray corresponds to a given line number in the original source file.
If multiple LineNumberTable attributes are present in the attributes table of a Code attribute, then they may appear in any order.
There may be more than one LineNumberTable attribute per line of a source file in the attributes table of a Code attribute. That is, LineNumberTable attributes may together represent a given line of a source file, and need not be one-to-one with source lines.
The LineNumberTable attribute has the following format:
LineNumberTable_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 line_number_table_length;
{ u2 start_pc;
u2 line_number;
} line_number_table[line_number_table_length];
}
The items of the LineNumberTable_attribute structure are as follows:
- attribute_name_index
-
The value of the
attribute_name_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Utf8_infostructure (§4.4.7) representing the string "LineNumberTable". - attribute_length
-
The value of the
attribute_lengthitem indicates the length of the attribute, excluding the initial six bytes. - line_number_table_length
-
The value of the
line_number_table_lengthitem indicates the number of entries in theline_number_tablearray. - line_number_table[]
-
Each entry in the
line_number_tablearray indicates that the line number in the original source file changes at a given point in thecodearray. Eachline_number_tableentry must contain the following two items:- start_pc
-
The value of the
start_pcitem must be a valid index into thecodearray of thisCodeattribute. The item indicates the index into thecodearray at which the code for a new line in the original source file begins. - line_number
-
The value of the
line_numberitem gives the corresponding line number in the original source file.
The LocalVariableTable attribute is an optional variable-length attribute in the attributes table of a Code attribute (§4.7.3). It may be used by debuggers to determine the value of a given local variable during the execution of a method.
If multiple LocalVariableTable attributes are present in the attributes table of a Code attribute, then they may appear in any order.
There may be no more than one LocalVariableTable attribute per local variable in the attributes table of a Code attribute.
The LocalVariableTable attribute has the following format:
LocalVariableTable_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 local_variable_table_length;
{ u2 start_pc;
u2 length;
u2 name_index;
u2 descriptor_index;
u2 index;
} local_variable_table[local_variable_table_length];
}
The items of the LocalVariableTable_attribute structure are as follows:
- attribute_name_index
-
The value of the
attribute_name_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Utf8_infostructure (§4.4.7) representing the string "LocalVariableTable". - attribute_length
-
The value of the
attribute_lengthitem indicates the length of the attribute, excluding the initial six bytes. - local_variable_table_length
-
The value of the
local_variable_table_lengthitem indicates the number of entries in thelocal_variable_tablearray. - local_variable_table[]
-
Each entry in the
local_variable_tablearray indicates a range ofcodearray offsets within which a local variable has a value, and indicates the index into the local variable array of the current frame at which that local variable can be found. Each entry must contain the following five items:- start_pc, length
-
The value of the
start_pcitem must be a valid index into thecodearray of thisCodeattribute and must be the index of the opcode of an instruction.The value of
start_pc + lengthmust either be a valid index into thecodearray of thisCodeattribute and be the index of the opcode of an instruction, or it must be the first index beyond the end of thatcodearray.The
start_pcandlengthitems indicate that the given local variable has a value at indices into thecodearray in the interval [start_pc,start_pc + length), that is, betweenstart_pcinclusive andstart_pc + lengthexclusive. - name_index
-
The value of the
name_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must contain aCONSTANT_Utf8_infostructure representing a valid unqualified name denoting a local variable (§4.2.2). - descriptor_index
-
The value of the
descriptor_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must contain aCONSTANT_Utf8_infostructure representing a field descriptor which encodes the type of a local variable in the source program (§4.3.2). - index
-
The value of the
indexitem must be a valid index into the local variable array of the current frame. The given local variable is atindexin the local variable array of the current frame.If the given local variable is of type
doubleorlong, it occupies bothindexandindex + 1.
The LocalVariableTypeTable attribute is an optional variable-length attribute in the attributes table of a Code attribute (§4.7.3). It may be used by debuggers to determine the value of a given local variable during the execution of a method.
If multiple LocalVariableTypeTable attributes are present in the attributes table of a given Code attribute, then they may appear in any order.
There may be no more than one LocalVariableTypeTable attribute per local variable in the attributes table of a Code attribute.
The LocalVariableTypeTable attribute differs from the LocalVariableTable attribute (§4.7.13) in that it provides signature information rather than descriptor information. This difference is only significant for variables whose type uses a type variable or parameterized type. Such variables will appear in both tables, while variables of other types will appear only in LocalVariableTable.
The LocalVariableTypeTable attribute has the following format:
LocalVariableTypeTable_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 local_variable_type_table_length;
{ u2 start_pc;
u2 length;
u2 name_index;
u2 signature_index;
u2 index;
} local_variable_type_table[local_variable_type_table_length];
}
The items of the LocalVariableTypeTable_attribute structure are as follows:
- attribute_name_index
-
The value of the
attribute_name_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Utf8_infostructure (§4.4.7) representing the string "LocalVariableTypeTable". - attribute_length
-
The value of the
attribute_lengthitem indicates the length of the attribute, excluding the initial six bytes. - local_variable_type_table_length
-
The value of the
local_variable_type_table_lengthitem indicates the number of entries in thelocal_variable_type_tablearray. - local_variable_type_table[]
-
Each entry in the
local_variable_type_tablearray indicates a range ofcodearray offsets within which a local variable has a value, and indicates the index into the local variable array of the current frame at which that local variable can be found. Each entry must contain the following five items:- start_pc, length
-
The value of the
start_pcitem must be a valid index into thecodearray of thisCodeattribute and must be the index of the opcode of an instruction.The value of
start_pc + lengthmust either be a valid index into thecodearray of thisCodeattribute and be the index of the opcode of an instruction, or it must be the first index beyond the end of thatcodearray.The
start_pcandlengthitems indicate that the given local variable has a value at indices into thecodearray in the interval [start_pc,start_pc + length), that is, betweenstart_pcinclusive andstart_pc + lengthexclusive. - name_index
-
The value of the
name_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must contain aCONSTANT_Utf8_infostructure representing a valid unqualified name denoting a local variable (§4.2.2). - signature_index
-
The value of the
signature_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must contain aCONSTANT_Utf8_infostructure representing a field signature which encodes the type of a local variable in the source program (§4.7.9.1). - index
-
The value of the
indexitem must be a valid index into the local variable array of the current frame. The given local variable is atindexin the local variable array of the current frame.If the given local variable is of type
doubleorlong, it occupies bothindexandindex + 1.
The Deprecated attribute is an optional fixed-length attribute in the attributes table of a ClassFile, field_info, or method_info structure (§4.1, §4.5, §4.6). A class, interface, method, or field may be marked using a Deprecated attribute to indicate that the class, interface, method, or field has been superseded.
A run-time interpreter or tool that reads the class file format, such as a compiler, can use this marking to advise the user that a superseded class, interface, method, or field is being referred to. The presence of a Deprecated attribute does not alter the semantics of a class or interface.
The Deprecated attribute has the following format:
Deprecated_attribute {
u2 attribute_name_index;
u4 attribute_length;
}
The items of the Deprecated_attribute structure are as follows:
- attribute_name_index
-
The value of the
attribute_name_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Utf8_infostructure (§4.4.7) representing the string "Deprecated". - attribute_length
The RuntimeVisibleAnnotations attribute is a variable-length attribute in the attributes table of a ClassFile, field_info, or method_info structure (§4.1, §4.5, §4.6). TheRuntimeVisibleAnnotations attribute records run-time visible annotations on the declaration of the corresponding class, field, or method.
There may be at most one RuntimeVisibleAnnotations attribute in the attributes table of a ClassFile, field_info, or method_info structure.
The RuntimeVisibleAnnotations attribute has the following format:
RuntimeVisibleAnnotations_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 num_annotations;
annotation annotations[num_annotations];
}
The items of the RuntimeVisibleAnnotations_attribute structure are as follows:
- attribute_name_index
-
The value of the
attribute_name_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Utf8_infostructure (§4.4.7) representing the string "RuntimeVisibleAnnotations". - attribute_length
-
The value of the
attribute_lengthitem indicates the length of the attribute, excluding the initial six bytes. - num_annotations
-
The value of the
num_annotationsitem gives the number of run-time visible annotations represented by the structure. - annotations[]
-
Each entry in the
annotationstable represents a single run-time visible annotation on a declaration. Theannotationstructure has the following format:annotation { u2 type_index; u2 num_element_value_pairs; { u2 element_name_index; element_value value; } element_value_pairs[num_element_value_pairs]; }The items of the
annotationstructure are as follows:- type_index
-
The value of the
type_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Utf8_infostructure (§4.4.7) representing a field descriptor (§4.3.2). The field descriptor denotes the type of the annotation represented by thisannotationstructure. - num_element_value_pairs
-
The value of the
num_element_value_pairsitem gives the number of element-value pairs of the annotation represented by thisannotationstructure. - element_value_pairs[]
-
Each value of the
element_value_pairstable represents a single element-value pair in the annotation represented by thisannotationstructure. Eachelement_value_pairsentry contains the following two items:- element_name_index
-
The value of the
element_name_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Utf8_infostructure (§4.4.7). Theconstant_poolentry denotes the name of the element of the element-value pair represented by thiselement_value_pairsentry.In other words, the entry denotes an element of the annotation type specified by
type_index. - value
-
The value of the
valueitem represents the value of the element-value pair represented by thiselement_value_pairsentry.
The element_value structure is a discriminated union representing the value of an element-value pair. It has the following format:
element_value {
u1 tag;
union {
u2 const_value_index;
{ u2 type_name_index;
u2 const_name_index;
} enum_const_value;
u2 class_info_index;
annotation annotation_value;
{ u2 num_values;
element_value values[num_values];
} array_value;
} value;
}
The tag item uses a single ASCII character to indicate the type of the value of the element-value pair. This determines which item of the value union is in use. Table 4.7.16.1-A shows the valid characters for the tag item, the type indicated by each character, and the item used in the value union for each character. The table's fourth column is used in the description below of one item of the value union.
Table 4.7.16.1-A. Interpretation of tag values as types
tag Item | Type | value Item | Constant Type |
|---|---|---|---|
B |
byte |
const_value_index |
CONSTANT_Integer |
C |
char |
const_value_index |
CONSTANT_Integer |
D |
double |
const_value_index |
CONSTANT_Double |
F |
float |
const_value_index |
CONSTANT_Float |
I |
int |
const_value_index |
CONSTANT_Integer |
J |
long |
const_value_index |
CONSTANT_Long |
S |
short |
const_value_index |
CONSTANT_Integer |
Z |
boolean |
const_value_index |
CONSTANT_Integer |
s |
String |
const_value_index |
CONSTANT_Utf8 |
e |
Enum type | enum_const_value |
Not applicable |
c |
Class |
class_info_index |
Not applicable |
@ |
Annotation type | annotation_value |
Not applicable |
[ |
Array type | array_value |
Not applicable |
The value item represents the value of an element-value pair. The item is a union, whose own items are as follows:
- const_value_index
-
The
const_value_indexitem denotes either a primitive constant value or aStringliteral as the value of this element-value pair.The value of the
const_value_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be of a type appropriate to thetagitem, as specified in the fourth column of Table 4.7.16.1-A. - enum_const_value
-
The
enum_const_valueitem denotes an enum constant as the value of this element-value pair.The
enum_const_valueitem consists of the following two items:- type_name_index
-
The value of the
type_name_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Utf8_infostructure (§4.4.7) representing a field descriptor (§4.3.2). Theconstant_poolentry gives the internal form of the binary name of the type of the enum constant represented by thiselement_valuestructure (§4.2.1). - const_name_index
-
The value of the
const_name_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Utf8_infostructure (§4.4.7). Theconstant_poolentry gives the simple name of the enum constant represented by thiselement_valuestructure.
- class_info_index
-
The
class_info_indexitem denotes a class literal as the value of this element-value pair.The
class_info_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Utf8_infostructure (§4.4.7) representing a return descriptor (§4.3.3). The return descriptor gives the type corresponding to the class literal represented by thiselement_valuestructure. Types correspond to class literals as follows:-
For a class literal C
.class, where C is the name of a class, interface, or array type, the corresponding type is C. The return descriptor in theconstant_poolwill be an ObjectType or an ArrayType. -
For a class literal p
.class, where p is the name of a primitive type, the corresponding type is p. The return descriptor in theconstant_poolwill be a BaseType character. -
For a class literal
void.class, the corresponding type isvoid. The return descriptor in theconstant_poolwill be V.
For example, the class literal
Object.classcorresponds to the typeObject, so theconstant_poolentry isLjava/lang/Object;, whereas the class literalint.classcorresponds to the typeint, so theconstant_poolentry isI.The class literal
void.classcorresponds tovoid, so theconstant_poolentry is V, whereas the class literalVoid.classcorresponds to the typeVoid, so theconstant_poolentry isLjava/lang/Void;. -
- annotation_value
-
The
annotation_valueitem denotes a "nested" annotation as the value of this element-value pair.The value of the
annotation_valueitem is anannotationstructure (§4.7.16) that gives the annotation represented by thiselement_valuestructure. - array_value
-
The
array_valueitem denotes an array as the value of this element-value pair.
The RuntimeInvisibleAnnotations attribute is a variable-length attribute in the attributes table of a ClassFile, field_info, or method_info structure (§4.1, §4.5, §4.6). TheRuntimeInvisibleAnnotations attribute records run-time invisible annotations on the declaration of the corresponding class, method, or field.
There may be at most one RuntimeInvisibleAnnotations attribute in the attributes table of a ClassFile, field_info, or method_info structure.
The RuntimeInvisibleAnnotations attribute is similar to the RuntimeVisibleAnnotations attribute (§4.7.16), except that the annotations represented by a RuntimeInvisibleAnnotations attribute must not be made available for return by reflective APIs, unless the Java Virtual Machine has been instructed to retain these annotations via some implementation-specific mechanism such as a command line flag. In the absence of such instructions, the Java Virtual Machine ignores this attribute.
The RuntimeInvisibleAnnotations attribute has the following format:
RuntimeInvisibleAnnotations_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 num_annotations;
annotation annotations[num_annotations];
}
The items of the RuntimeInvisibleAnnotations_attribute structure are as follows:
- attribute_name_index
-
The value of the
attribute_name_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Utf8_infostructure (§4.4.7) representing the string "RuntimeInvisibleAnnotations". - attribute_length
-
The value of the
attribute_lengthitem indicates the length of the attribute, excluding the initial six bytes. - num_annotations
-
The value of the
num_annotationsitem gives the number of run-time invisible annotations represented by the structure. - annotations[]
-
Each entry in the
annotationstable represents a single run-time invisible annotation on a declaration. Theannotationstructure is specified in §4.7.16.
The RuntimeVisibleParameterAnnotations attribute is a variable-length attribute in the attributes table of the method_info structure (§4.6). TheRuntimeVisibleParameterAnnotations attribute records run-time visible annotations on the declarations of formal parameters of the corresponding method.
There may be at most one RuntimeVisibleParameterAnnotations attribute in the attributes table of a method_info structure.
The RuntimeVisibleParameterAnnotations attribute has the following format:
RuntimeVisibleParameterAnnotations_attribute {
u2 attribute_name_index;
u4 attribute_length;
u1 num_parameters;
{ u2 num_annotations;
annotation annotations[num_annotations];
} parameter_annotations[num_parameters];
}
The items of the RuntimeVisibleParameterAnnotations_attribute structure are as follows:
- attribute_name_index
-
The value of the
attribute_name_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Utf8_infostructure (§4.4.7) representing the string "RuntimeVisibleParameterAnnotations". - attribute_length
-
The value of the
attribute_lengthitem indicates the length of the attribute, excluding the initial six bytes. - num_parameters
-
The value of the
num_parametersitem gives the number of run-time visible parameter annotations represented by this structure.There is no assurance that this number is the same as the number of parameter descriptors in the method descriptor.
- parameter_annotations[]
-
Each entry in the
parameter_annotationstable represents all of the run-time visible annotations on the declaration of a single formal parameter. Eachparameter_annotationsentry contains the following two items:- num_annotations
-
The value of the
num_annotationsitem indicates the number of run-time visible annotations on the declaration of the formal parameter corresponding to theparameter_annotationsentry. - annotations[]
-
Each entry in the
annotationstable represents a single run-time visible annotation on the declaration of the formal parameter corresponding to theparameter_annotationsentry. Theannotationstructure is specified in §4.7.16.
The i'th entry in the
parameter_annotationstable may, but is not required to, correspond to the i'th parameter descriptor in the method descriptor (§4.3.3).For example, a compiler may choose to create entries in the table corresponding only to those parameter descriptors which represent explicitly declared parameters in source code. In the Java programming language, a constructor of an inner class is specified to have an implicitly declared parameter before its explicitly declared parameters (JLS §8.8.1), so the corresponding
<init>method in aclassfile has a parameter descriptor representing the implicitly declared parameter before any parameter descriptors representing explicitly declared parameters. If the first explicitly declared parameter is annotated in source code, then a compiler may createparameter_annotations[0]to store annotations corresponding to the second parameter descriptor.
The RuntimeInvisibleParameterAnnotations attribute is a variable-length attribute in the attributes table of a method_info structure (§4.6). TheRuntimeInvisibleParameterAnnotations attribute records run-time invisible annotations on the declarations of formal parameters of the corresponding method.
There may be at most one RuntimeInvisibleParameterAnnotations attribute in the attributes table of a method_info structure.
The RuntimeInvisibleParameterAnnotations attribute is similar to the RuntimeVisibleParameterAnnotations attribute (§4.7.18), except that the annotations represented by a RuntimeInvisibleParameterAnnotations attribute must not be made available for return by reflective APIs, unless the Java Virtual Machine has specifically been instructed to retain these annotations via some implementation-specific mechanism such as a command line flag. In the absence of such instructions, the Java Virtual Machine ignores this attribute.
The RuntimeInvisibleParameterAnnotations attribute has the following format:
RuntimeInvisibleParameterAnnotations_attribute {
u2 attribute_name_index;
u4 attribute_length;
u1 num_parameters;
{ u2 num_annotations;
annotation annotations[num_annotations];
} parameter_annotations[num_parameters];
}
The items of the RuntimeInvisibleParameterAnnotations_attribute structure are as follows:
- attribute_name_index
-
The value of the
attribute_name_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Utf8_infostructure (§4.4.7) representing the string "RuntimeInvisibleParameterAnnotations". - attribute_length
-
The value of the
attribute_lengthitem indicates the length of the attribute, excluding the initial six bytes. - num_parameters
-
The value of the
num_parametersitem gives the number of run-time invisible parameter annotations represented by this structure.There is no assurance that this number is the same as the number of parameter descriptors in the method descriptor.
- parameter_annotations[]
-
Each entry in the
parameter_annotationstable represents all of the run-time invisible annotations on the declaration of a single formal parameter. Eachparameter_annotationsentry contains the following two items:- num_annotations
-
The value of the
num_annotationsitem indicates the number of run-time invisible annotations on the declaration of the formal parameter corresponding to theparameter_annotationsentry. - annotations[]
-
Each entry in the
annotationstable represents a single run-time invisible annotation on the declaration of the formal parameter corresponding to theparameter_annotationsentry. Theannotationstructure is specified in §4.7.16.
The i'th entry in the
parameter_annotationstable may, but is not required to, correspond to the i'th parameter descriptor in the method descriptor (§4.3.3).See the note in §4.7.18 for an example of when
parameter_annotations[0]does not correspond to the first parameter descriptor in the method descriptor.
The RuntimeVisibleTypeAnnotations attribute is an variable-length attribute in the attributes table of a ClassFile, field_info, or method_info structure, or Code attribute (§4.1, §4.5, §4.6, §4.7.3). The RuntimeVisibleTypeAnnotations attribute records run-time visible annotations on types used in the declaration of the corresponding class, field, or method, or in an expression in the corresponding method body. The RuntimeVisibleTypeAnnotations attribute also records run-time visible annotations on type parameter declarations of generic classes, interfaces, methods, and constructors.
There may be at most one RuntimeVisibleTypeAnnotations attribute in the attributes table of a ClassFile, field_info, or method_info structure, or Code attribute.
An attributes table contains a RuntimeVisibleTypeAnnotations attribute only if types are annotated in kinds of declaration or expression that correspond to the parent structure or attribute of the attributes table.
For example, all annotations on types in the implements clause of a class declaration are recorded in the RuntimeVisibleTypeAnnotations attribute of the class's ClassFile structure. Meanwhile, all annotations on the type in a field declaration are recorded in the RuntimeVisibleTypeAnnotations attribute of the field's field_info structure.
The RuntimeVisibleTypeAnnotations attribute has the following format:
RuntimeVisibleTypeAnnotations_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 num_annotations;
type_annotation annotations[num_annotations];
}
The items of the RuntimeVisibleTypeAnnotations_attribute structure are as follows:
- attribute_name_index
-
The value of the
attribute_name_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Utf8_infostructure representing the string "RuntimeVisibleTypeAnnotations". - attribute_length
-
The value of the
attribute_lengthitem indicates the length of the attribute, excluding the initial six bytes. - num_annotations
-
The value of the
num_annotationsitem gives the number of run-time visible type annotations represented by the structure. - annotations[]
-
Each entry in the
annotationstable represents a single run-time visible annotation on a type used in a declaration or expression. Thetype_annotationstructure has the following format:type_annotation { u1 target_type; union { type_parameter_target; supertype_target; type_parameter_bound_target; empty_target; formal_parameter_target; throws_target; localvar_target; catch_target; offset_target; type_argument_target; } target_info; type_path target_path; u2 type_index; u2 num_element_value_pairs; { u2 element_name_index; element_value value; } element_value_pairs[num_element_value_pairs]; }The first three items -
target_type,target_info, andtarget_path- specify the precise location of the annotated type. The last three items -type_index,num_element_value_pairs, andelement_value_pairs[]- specify the annotation's own type and element-value pairs.The items of the
type_annotationstructure are as follows:- target_type
-
The value of the
target_typeitem denotes the kind of target on which the annotation appears. The various kinds of target correspond to the type contexts of the Java programming language where types are used in declarations and expressions (JLS §4.11).The legal values of
target_typeare specified in Table 4.7.20-A and Table 4.7.20-B. Each value is a one-byte tag indicating which item of thetarget_infounion follows thetarget_typeitem to give more information about the target.The kinds of target in Table 4.7.20-A and Table 4.7.20-B correspond to the type contexts in JLS §4.11. Namely,
target_typevalues 0x10-0x17 and 0x40-0x42 correspond to type contexts 1-10, whiletarget_typevalues 0x43-0x4B correspond to type contexts 11-16.The value of the
target_typeitem determines whether thetype_annotationstructure appears in aRuntimeVisibleTypeAnnotationsattribute in aClassFilestructure, afield_infostructure, amethod_infostructure, or aCodeattribute. Table 4.7.20-C gives the location of theRuntimeVisibleTypeAnnotationsattribute for atype_annotationstructure with each legaltarget_typevalue. - target_info
-
The value of the
target_infoitem denotes precisely which type in a declaration or expression is annotated.The items of the
target_infounion are specified in §4.7.20.1. - target_path
-
The value of the
target_pathitem denotes precisely which part of the type indicated bytarget_infois annotated.The format of the
type_pathstructure is specified in §4.7.20.2. - type_index, num_element_value_pairs, element_value_pairs[]
-
The meaning of these items in the
type_annotationstructure is the same as their meaning in theannotationstructure (§4.7.16).
Table 4.7.20-A. Interpretation of target_type values (Part 1)
| Value | Kind of target | target_info item |
|---|---|---|
| 0x00 | type parameter declaration of generic class or interface | type_parameter_target |
| 0x01 | type parameter declaration of generic method or constructor | type_parameter_target |
| 0x10 | type in extends or implements clause of class declaration (including the direct superclass or direct superinterface of an anonymous class declaration), or in extends clause of interface declaration |
supertype_target |
| 0x11 | type in bound of type parameter declaration of generic class or interface | type_parameter_bound_target |
| 0x12 | type in bound of type parameter declaration of generic method or constructor | type_parameter_bound_target |
| 0x13 | type in field declaration | empty_target |
| 0x14 | return type of method, or type of newly constructed object | empty_target |
| 0x15 | receiver type of method or constructor | empty_target |
| 0x16 | type in formal parameter declaration of method, constructor, or lambda expression | formal_parameter_target |
| 0x17 | type in throws clause of method or constructor |
throws_target |
Table 4.7.20-B. Interpretation of target_type values (Part 2)
| Value | Kind of target | target_info item |
|---|---|---|
| 0x40 | type in local variable declaration | localvar_target |
| 0x41 | type in resource variable declaration | localvar_target |
| 0x42 | type in exception parameter declaration | catch_target |
| 0x43 | type in instanceof expression | offset_target |
| 0x44 | type in new expression | offset_target |
| 0x45 | type in method reference expression using ::new |
offset_target |
| 0x46 | type in method reference expression using ::Identifier |
offset_target |
| 0x47 | type in cast expression | type_argument_target |
| 0x48 | type argument for generic constructor in new expression or explicit constructor invocation statement | type_argument_target |
| 0x49 | type argument for generic method in method invocation expression | type_argument_target |
| 0x4A | type argument for generic constructor in method reference expression using ::new |
type_argument_target |
| 0x4B | type argument for generic method in method reference expression using ::Identifier |
type_argument_target |
Table 4.7.20-C. Location of enclosing attribute for target_type values
| Value | Kind of target | Location |
|---|---|---|
| 0x00 | type parameter declaration of generic class or interface | ClassFile |
| 0x01 | type parameter declaration of generic method or constructor | method_info |
| 0x10 | type in extends clause of class or interface declaration, or in implements clause of interface declaration |
ClassFile |
| 0x11 | type in bound of type parameter declaration of generic class or interface | ClassFile |
| 0x12 | type in bound of type parameter declaration of generic method or constructor | method_info |
| 0x13 | type in field declaration | field_info |
| 0x14 | return type of method or constructor | method_info |
| 0x15 | receiver type of method or constructor | method_info |
| 0x16 | type in formal parameter declaration of method, constructor, or lambda expression | method_info |
| 0x17 | type in throws clause of method or constructor |
method_info |
| 0x40-0x4B | types in local variable declarations, resource variable declarations, exception parameter declarations, expressions | Code |
The items of the target_info union (except for the first) specify precisely which type in a declaration or expression is annotated. The first item specifies not which type, but rather which declaration of a type parameter is annotated. The items are as follows:
-
The
type_parameter_targetitem indicates that an annotation appears on the declaration of the i'th type parameter of a generic class, generic interface, generic method, or generic constructor.type_parameter_target { u1 type_parameter_index; }The value of the
type_parameter_indexitem specifies which type parameter declaration is annotated. Atype_parameter_indexvalue of0specifies the first type parameter declaration. -
The
supertype_targetitem indicates that an annotation appears on a type in theextendsorimplementsclause of a class or interface declaration.supertype_target { u2 supertype_index; }A
supertype_indexvalue of 65535 specifies that the annotation appears on the superclass in anextendsclause of a class declaration.Any other
supertype_indexvalue is an index into theinterfacesarray of the enclosingClassFilestructure, and specifies that the annotation appears on that superinterface in either theimplementsclause of a class declaration or theextendsclause of an interface declaration. -
The
type_parameter_bound_targetitem indicates that an annotation appears on the i'th bound of the j'th type parameter declaration of a generic class, interface, method, or constructor.type_parameter_bound_target { u1 type_parameter_index; u1 bound_index; }The value of the of
type_parameter_indexitem specifies which type parameter declaration has an annotated bound. Atype_parameter_indexvalue of0specifies the first type parameter declaration.The value of the
bound_indexitem specifies which bound of the type parameter declaration indicated bytype_parameter_indexis annotated. Abound_indexvalue of0specifies the first bound of a type parameter declaration.The
type_parameter_bound_targetitem records that a bound is annotated, but does not record the type which constitutes the bound. The type may be found by inspecting the class signature or method signature stored in the appropriateSignatureattribute. -
The
empty_targetitem indicates that an annotation appears on either the type in a field declaration, the return type of a method, the type of a newly constructed object, or the receiver type of a method or constructor.empty_target { }Only one type appears in each of these locations, so there is no per-type information to represent in the
target_infounion. -
The
formal_parameter_targetitem indicates that an annotation appears on the type in a formal parameter declaration of a method, constructor, or lambda expression.formal_parameter_target { u1 formal_parameter_index; }The value of the
formal_parameter_indexitem specifies which formal parameter declaration has an annotated type. Aformal_parameter_indexvalue of i may, but is not required to, correspond to the i'th parameter descriptor in the method descriptor (§4.3.3).The
formal_parameter_targetitem records that a formal parameter's type is annotated, but does not record the type itself. The type may be found by inspecting the method descriptor, although aformal_parameter_indexvalue of0does not always indicate the first parameter descriptor in the method descriptor; see the note in §4.7.18 for a similar situation involving theparameter_annotationstable. -
The
throws_targetitem indicates that an annotation appears on the i'th type in thethrowsclause of a method or constructor declaration.throws_target { u2 throws_type_index; }The value of the
throws_type_indexitem is an index into theexception_index_tablearray of theExceptionsattribute of themethod_infostructure enclosing theRuntimeVisibleTypeAnnotationsattribute. -
The
localvar_targetitem indicates that an annotation appears on the type in a local variable declaration, including a variable declared as a resource in atry-with-resources statement.localvar_target { u2 table_length; { u2 start_pc; u2 length; u2 index; } table[table_length]; }The value of the
table_lengthitem gives the number of entries in thetablearray. Each entry indicates a range ofcodearray offsets within which a local variable has a value. It also indicates the index into the local variable array of the current frame at which that local variable can be found. Each entry contains the following three items:- start_pc, length
-
The given local variable has a value at indices into the
codearray in the interval [start_pc,start_pc + length), that is, betweenstart_pcinclusive andstart_pc + lengthexclusive. - index
-
The given local variable must be at
indexin the local variable array of the current frame.If the local variable at
indexis of typedoubleorlong, it occupies bothindexandindex + 1.
A table is needed to fully specify the local variable whose type is annotated, because a single local variable may be represented with different local variable indices over multiple live ranges. The
start_pc,length, andindexitems in each table entry specify the same information as aLocalVariableTableattribute.The
localvar_targetitem records that a local variable's type is annotated, but does not record the type itself. The type may be found by inspecting the appropriateLocalVariableTableattribute. -
The
catch_targetitem indicates that an annotation appears on the i'th type in an exception parameter declaration.catch_target { u2 exception_table_index; }The value of the
exception_table_indexitem is an index into theexception_tablearray of theCodeattribute enclosing theRuntimeVisibleTypeAnnotationsattribute.The possibility of more than one type in an exception parameter declaration arises from the multi-
catchclause of thetrystatement, where the type of the exception parameter is a union of types (JLS §14.20). A compiler usually creates oneexception_tableentry for each type in the union, which allows thecatch_targetitem to distinguish them. This preserves the correspondence between a type and its annotations. -
The
offset_targetitem indicates that an annotation appears on either the type in an instanceof expression or a new expression, or the type before the::in a method reference expression.offset_target { u2 offset; }The value of the
offsetitem specifies thecodearray offset of either the bytecode instruction corresponding to the instanceof expression, the new bytecode instruction corresponding to the new expression, or the bytecode instruction corresponding to the method reference expression. -
The
type_argument_targetitem indicates that an annotation appears either on the i'th type in a cast expression, or on the i'th type argument in the explicit type argument list for any of the following: a new expression, an explicit constructor invocation statement, a method invocation expression, or a method reference expression.type_argument_target { u2 offset; u1 type_argument_index; }The value of the
offsetitem specifies thecodearray offset of either the bytecode instruction corresponding to the cast expression, the new bytecode instruction corresponding to the newexpression, the bytecode instruction corresponding to the explicit constructor invocation statement, the bytecode instruction corresponding to the method invocation expression, or the bytecode instruction corresponding to the method reference expression.For a cast expression, the value of the
type_argument_indexitem specifies which type in the cast operator is annotated. Atype_argument_indexvalue of0specifies the first (or only) type in the cast operator.The possibility of more than one type in a cast expression arises from a cast to an intersection type.
For an explicit type argument list, the value of the
type_argument_indexitem specifies which type argument is annotated. Atype_argument_indexvalue of0specifies the first type argument.
Wherever a type is used in a declaration or expression, the type_path structure identifies which part of the type is annotated. An annotation may appear on the type itself, but if the type is a reference type, then there are additional locations where an annotation may appear:
-
If an array type T
[]is used in a declaration or expression, then an annotation may appear on any component type of the array type, including the element type. -
If a nested type T1
.T2 is used in a declaration or expression, then an annotation may appear on the name of the top level type or any member type. -
If a parameterized type T
<A>or T<? extends A>or T<? super A>is used in a declaration or expression, then an annotation may appear on any type argument or on the bound of any wildcard type argument.
For example, consider the different parts of String[][] that are annotated in:
@Foo String[][] // Annotates the class type String String @Foo [][] // Annotates the array type String[][] String[] @Foo [] // Annotates the array type String[]
or the different parts of the nested type Outer.Middle.Inner that are annotated in:
@Foo Outer.Middle.Inner Outer.@Foo Middle.Inner Outer.Middle.@Foo Inner
or the different parts of the parameterized types Map<String,Object> and List<...> that are annotated in:
@Foo Map<String,Object> Map<@Foo String,Object> Map<String,@Foo Object> List<@Foo ? extends String> List<? extends @Foo String>
The type_path structure has the following format:
type_path {
u1 path_length;
{ u1 type_path_kind;
u1 type_argument_index;
} path[path_length];
}
The value of the path_length item gives the number of entries in the path array:
-
If the value of
path_lengthis0, then the annotation appears directly on the type itself. -
If the value of
path_lengthis non-zero, then each entry in thepatharray represents an iterative, left-to-right step towards the precise location of the annotation in an array type, nested type, or parameterized type. (In an array type, the iteration visits the array type itself, then its component type, then the component type of that component type, and so on, until the element type is reached.) Each entry contains the following two items:- type_path_kind
-
The legal values for the
type_path_kinditem are listed in Table 4.7.20.2-A. - type_argument_index
-
If the value of the
type_path_kinditem is0,1, or2, then the value of thetype_argument_indexitem is0.If the value of the
type_path_kinditem is3, then the value of thetype_argument_indexitem specifies which type argument of a parameterized type is annotated, where0indicates the first type argument of a parameterized type.
Table 4.7.20.2-B. type_path structures for @A Map<@B ? extends @C String, @D List<@E Object>>
| Annotation | path_length | path |
|---|---|---|
@A |
0 |
[] |
@B |
1 |
[{type_path_kind: 3; type_argument_index: 0}] |
@C |
2 |
[{type_path_kind: 3; type_argument_index: 0}, {type_path_kind: 2; type_argument_index: 0}] |
@D |
1 |
[{type_path_kind: 3; type_argument_index: 1}] |
@E |
2 |
[{type_path_kind: 3; type_argument_index: 1}, {type_path_kind: 3; type_argument_index: 0}] |
Table 4.7.20.2-C. type_path structures for @I String @F [] @G [] @H []
| Annotation | path_length | path |
|---|---|---|
@F |
0 |
[] |
@G |
1 |
[{type_path_kind: 0; type_argument_index: 0}] |
@H |
2 |
[{type_path_kind: 0; type_argument_index: 0}, {type_path_kind: 0; type_argument_index: 0}] |
@I |
3 |
[{type_path_kind: 0; type_argument_index: 0}, {type_path_kind: 0; type_argument_index: 0}, {type_path_kind: 0; type_argument_index: 0}] |
Table 4.7.20.2-D. type_path structures for @A List<@B Comparable<@F Object @C [] @D [] @E []>>
| Annotation | path_length | path |
|---|---|---|
@A |
0 |
[] |
@B |
1 |
[{type_path_kind: 3; type_argument_index: 0}] |
@C |
2 |
[{type_path_kind: 3; type_argument_index: 0}, {type_path_kind: 3; type_argument_index: 0}] |
@D |
3 |
[{type_path_kind: 3; type_argument_index: 0}, {type_path_kind: 3; type_argument_index: 0}, {type_path_kind: 0; type_argument_index: 0}] |
@E |
4 |
[{type_path_kind: 3; type_argument_index: 0}, {type_path_kind: 3; type_argument_index: 0}, {type_path_kind: 0; type_argument_index: 0}, {type_path_kind: 0; type_argument_index: 0}] |
@F |
5 |
[{type_path_kind: 3; type_argument_index: 0}, {type_path_kind: 3; type_argument_index: 0}, {type_path_kind: 0; type_argument_index: 0}, {type_path_kind: 0; type_argument_index: 0}, {type_path_kind: 0; type_argument_index: 0}] |
Table 4.7.20.2-E. type_path structures for @C Outer . @B Middle . @A Inner
| Annotation | path_length | path |
|---|---|---|
@A |
2 |
[{type_path_kind: 1; type_argument_index: 0}, {type_path_kind: 1; type_argument_index: 0}] |
@B |
1 |
[{type_path_kind: 1; type_argument_index: 0}] |
@C |
0 |
[] |
Table 4.7.20.2-F. type_path structures for Outer . Middle<@D Foo . @C Bar> . Inner<@B String @A []>
| Annotation | path_length | path |
|---|---|---|
@A |
3 |
[{type_path_kind: 1; type_argument_index: 0}, {type_path_kind: 1; type_argument_index: 0}, {type_path_kind: 3; type_argument_index: 0}] |
@B |
4 |
[{type_path_kind: 1; type_argument_index: 0}, {type_path_kind: 1; type_argument_index: 0}, {type_path_kind: 3; type_argument_index: 0}, {type_path_kind: 0; type_argument_index: 0}] |
@C |
3 |
[{type_path_kind: 1; type_argument_index: 0}, {type_path_kind: 3; type_argument_index: 0}, {type_path_kind: 1; type_argument_index: 0}] |
@D |
2 |
[{type_path_kind: 1; type_argument_index: 0}, {type_path_kind: 3; type_argument_index: 0}] |
The RuntimeInvisibleTypeAnnotations attribute is an variable-length attribute in the attributes table of a ClassFile, field_info, or method_info structure, or Code attribute (§4.1, §4.5, §4.6, §4.7.3). The RuntimeInvisibleTypeAnnotations attribute records run-time invisible annotations on types used in the corresponding declaration of a class, field, or method, or in an expression in the corresponding method body. The RuntimeInvisibleTypeAnnotations attribute also records annotations on type parameter declarations of generic classes, interfaces, methods, and constructors.
There may be at most one RuntimeInvisibleTypeAnnotations attribute in the attributes table of a ClassFile, field_info, or method_info structure, or Code attribute.
An attributes table contains a RuntimeInvisibleTypeAnnotations attribute only if types are annotated in kinds of declaration or expression that correspond to the parent structure or attribute of the attributes table.
The RuntimeInvisibleTypeAnnotations attribute has the following format:
RuntimeInvisibleTypeAnnotations_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 num_annotations;
type_annotation annotations[num_annotations];
}
The items of the RuntimeInvisibleTypeAnnotations_attribute structure are as follows:
- attribute_name_index
-
The value of the
attribute_name_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Utf8_infostructure representing the string "RuntimeInvisibleTypeAnnotations". - attribute_length
-
The value of the
attribute_lengthitem indicates the length of the attribute, excluding the initial six bytes. - num_annotations
-
The value of the
num_annotationsitem gives the number of run-time invisible type annotations represented by the structure. - annotations[]
-
Each entry in the
annotationstable represents a single run-time invisible annotation on a type used in a declaration or expression. Thetype_annotationstructure is specified in§4.7.20.
The AnnotationDefault attribute is a variable-length attribute in the attributes table of certain method_info structures (§4.6), namely those representing elements of annotation types (JLS §9.6.1). The AnnotationDefault attribute records the default value (JLS §9.6.2) for the element represented by the method_info structure.
There may be at most one AnnotationDefault attribute in the attributes table of a method_info structure which represents an element of an annotation type.
The AnnotationDefault attribute has the following format:
AnnotationDefault_attribute {
u2 attribute_name_index;
u4 attribute_length;
element_value default_value;
}
The items of the AnnotationDefault_attribute structure are as follows:
- attribute_name_index
-
The value of the
attribute_name_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Utf8_infostructure (§4.4.7) representing the string "AnnotationDefault". - attribute_length
-
The value of the
attribute_lengthitem indicates the length of the attribute, excluding the initial six bytes. - default_value
-
The
default_valueitem represents the default value of the annotation type element represented by themethod_infostructure enclosing thisAnnotationDefaultattribute.
The BootstrapMethods attribute is a variable-length attribute in the attributes table of a ClassFile structure (§4.1). The BootstrapMethods attribute records bootstrap method specifiers referenced by invokedynamic instructions (§invokedynamic).
There must be exactly one BootstrapMethods attribute in the attributes table of a ClassFile structure if the constant_pool table of the ClassFile structure has at least oneCONSTANT_InvokeDynamic_info entry (§4.4.10).
There may be at most one BootstrapMethods attribute in the attributes table of a ClassFile structure.
The BootstrapMethods attribute has the following format:
BootstrapMethods_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 num_bootstrap_methods;
{ u2 bootstrap_method_ref;
u2 num_bootstrap_arguments;
u2 bootstrap_arguments[num_bootstrap_arguments];
} bootstrap_methods[num_bootstrap_methods];
}
The items of the BootstrapMethods_attribute structure are as follows:
- attribute_name_index
-
The value of the
attribute_name_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Utf8_infostructure (§4.4.7) representing the string "BootstrapMethods". - attribute_length
-
The value of the
attribute_lengthitem indicates the length of the attribute, excluding the initial six bytes.The value of the
attribute_lengthitem is thus dependent on the number of invokedynamic instructions in thisClassFilestructure. - num_bootstrap_methods
-
The value of the
num_bootstrap_methodsitem determines the number of bootstrap method specifiers in thebootstrap_methodsarray. - bootstrap_methods[]
-
Each entry in the
bootstrap_methodstable contains an index to aCONSTANT_MethodHandle_infostructure which specifies a bootstrap method, and a sequence (perhaps empty) of indexes to static arguments for the bootstrap method.Each
bootstrap_methodsentry must contain the following three items:- bootstrap_method_ref
-
The value of the
bootstrap_method_refitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_MethodHandle_infostructure (§4.4.8).The form of the method handle is driven by the continuing resolution of the call site specifier in §invokedynamic, where execution of the
invokemethod ofjava.lang.invoke.MethodHandlerequires that the bootstrap method handle be adjustable to the actual arguments being passed, as if by invocation of theasTypemethod ofjava.lang.invoke.MethodHandle. Accordingly, thereference_kinditem of theCONSTANT_MethodHandle_infostructure should have the value 6 or 8 (§5.4.3.5), and thereference_indexitem should specify a static method or constructor that takes three arguments of typejava.lang.invoke.MethodHandles.Lookup,String, andjava.lang.invoke.MethodType, in that order. Otherwise, invocation of the bootstrap method handle during call site specifier resolution will complete abruptly. - num_bootstrap_arguments
-
The value of the
num_bootstrap_argumentsitem gives the number of items in thebootstrap_argumentsarray. - bootstrap_arguments[]
-
Each entry in the
bootstrap_argumentsarray must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_String_info,CONSTANT_Class_info,CONSTANT_Integer_info,CONSTANT_Long_info,CONSTANT_Float_info,CONSTANT_Double_info,CONSTANT_MethodHandle_info, orCONSTANT_MethodType_infostructure (§4.4.3, §4.4.1, §4.4.4, §4.4.5, §4.4.8, §4.4.9).
The MethodParameters attribute is a variable-length attribute in the attributes table of a method_info structure (§4.6). A MethodParameters attribute records information about the formal parameters of a method, such as their names.
There may be at most one MethodParameters attribute in the attributes table of a method_info structure.
The MethodParameters attribute has the following format:
MethodParameters_attribute {
u2 attribute_name_index;
u4 attribute_length;
u1 parameters_count;
{ u2 name_index;
u2 access_flags;
} parameters[parameters_count];
}
The items of the MethodParameters_attribute structure are as follows:
- attribute_name_index
-
The value of the
attribute_name_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Utf8_infostructure representing the string "MethodParameters". - attribute_length
-
The value of the
attribute_lengthitem indicates the length of the attribute, excluding the initial six bytes. - parameters_count
-
The value of the
parameters_countitem indicates the number of parameter descriptors in the method descriptor (§4.3.3) referenced by thedescriptor_indexof the attribute's enclosingmethod_infostructure.This is not a constraint which a Java Virtual Machine implementation must enforce during format checking (§4.8). The task of matching parameter descriptors in a method descriptor against the items in the
parametersarray below is done by the reflection libraries of the Java SE Platform. - parameters[]
-
Each entry in the
parametersarray contains the following pair of items:- name_index
-
The value of the
name_indexitem must either be zero or a valid index into theconstant_pooltable.If the value of the
name_indexitem is zero, then thisparameterselement indicates a formal parameter with no name.If the value of the
name_indexitem is nonzero, theconstant_poolentry at that index must be aCONSTANT_Utf8_infostructure representing a valid unqualified name denoting a formal parameter (§4.2.2). - access_flags
-
The value of the
access_flagsitem is as follows:- 0x0010 (
ACC_FINAL) - 0x1000 (
ACC_SYNTHETIC) -
Indicates that the formal parameter was not explicitly or implicitly declared in source code, according to the specification of the language in which the source code was written (JLS §13.1). (The formal parameter is an implementation artifact of the compiler which produced this
classfile.) - 0x8000 (
ACC_MANDATED) -
Indicates that the formal parameter was implicitly declared in source code, according to the specification of the language in which the source code was written (JLS §13.1). (The formal parameter is mandated by a language specification, so all compilers for the language must emit it.)
- 0x0010 (
The i'th entry in the parameters array corresponds to the i'th parameter descriptor in the enclosing method's descriptor. (The parameters_count item is one byte because a method descriptor is limited to 255 parameters.) Effectively, this means the parameters array stores information for all the parameters of the method. One could imagine other schemes, where entries in the parameters array specify their corresponding parameter descriptors, but it would unduly complicate the MethodParameters attribute.
The i'th entry in the parameters array may or may not correspond to the i'th type in the enclosing method's Signature attribute (if present), or to the i'th annotation in the enclosing method's parameter annotations.
The Module attribute is a variable-length attribute in the attributes table of a ClassFile structure. The Module attribute indicates the modules required by a module; the packages exported and opened by a module; and the services used and provided by a module.
There may be at most one Module attribute in the attributes table of a ClassFile structure.
The Module attribute has the following format:
Module_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 module_name_index;
u2 module_flags;
u2 module_version_index;
u2 requires_count;
{ u2 requires_index;
u2 requires_flags;
u2 requires_version_index;
} requires[requires_count];
u2 exports_count;
{ u2 exports_index;
u2 exports_flags;
u2 exports_to_count;
u2 exports_to_index[exports_to_count];
} exports[exports_count];
u2 opens_count;
{ u2 opens_index;
u2 opens_flags;
u2 opens_to_count;
u2 opens_to_index[opens_to_count];
} opens[opens_count];
u2 uses_count;
u2 uses_index[uses_count];
u2 provides_count;
{ u2 provides_index;
u2 provides_with_count;
u2 provides_with_index[provides_with_count];
} provides[provides_count];
}
The items of the Module_attribute structure are as follows:
- attribute_name_index
-
The value of the
attribute_name_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Utf8_infostructure representing the string "Module". - attribute_length
-
The value of the
attribute_lengthitem is the length of the attribute excluding the initial six bytes. - module_name_index
-
The value of the
module_name_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Module_infostructure denoting the current module. - module_flags
- module_version_index
-
The value of the
module_version_indexitem must be either zero or a valid index into theconstant_pooltable. If the value of the item is zero, then no version information about the current module is present. If the value of the item is nonzero, then theconstant_poolentry at that index must be aCONSTANT_Utf8_infostructure representing the version of the current module. - requires_count
-
The value of the
requires_countitem indicates the number of entries in therequirestable.If the current module is
java.base, thenrequires_countmust be zero.If the current module is not
java.base, thenrequires_countmust be at least one. - requires[]
-
Each entry in the
requirestable specifies a dependence of the current module. The items in each entry are as follows:- requires_index
-
The value of the
requires_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Module_infostructure denoting a module on which the current module depends.At most one entry in the
requirestable may specify a module of a given name with itsrequires_indexitem. - requires_flags
-
The value of the
requires_flagsitem is as follows:- 0x0020 (
ACC_TRANSITIVE) -
Indicates that any module which depends on the current module, implicitly declares a dependence on the module indicated by this entry.
- 0x0040 (
ACC_STATIC_PHASE) -
Indicates that this dependence is mandatory in the static phase, i.e., at compile time, but is optional in the dynamic phase, i.e., at run time.
- 0x1000 (
ACC_SYNTHETIC) -
Indicates that this dependence was not explicitly or implicitly declared in the source of the module declaration.
- 0x8000 (
ACC_MANDATED) -
Indicates that this dependence was implicitly declared in the source of the module declaration.
- 0x0020 (
- requires_version_index
-
The value of the
requires_version_indexitem must be either zero or a valid index into theconstant_pooltable. If the value of the item is zero, then no version information about the dependence is present. If the value of the item is nonzero, then theconstant_poolentry at that index must be aCONSTANT_Utf8_infostructure representing the version of the module specified byrequires_index.
Unless the current module is
java.base, exactly one entry in therequirestable must have both arequires_indexitem which indicatesjava.baseand arequires_flagsitem which has theACC_SYNTHETICflag not set. - exports_count
-
The value of the
exports_countitem indicates the number of entries in theexportstable. - exports[]
-
Each entry in the
exportstable specifies a package exported by the current module, such thatpublicandprotectedtypes in the package, and theirpublicandprotectedmembers, may be accessed from outside the current module, possibly from a limited set of "friend" modules.The items in each entry are as follows:
- exports_index
-
The value of the
exports_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Package_infostructure representing a package exported by the current module.At most one entry in the
exportstable may specify a package of a given name with itsexports_indexitem. - exports_flags
- exports_to_count
-
The value of the
exports_to_countindicates the number of entries in theexports_to_indextable.If
exports_to_countis zero, then this package is exported by the current module in an unqualified fashion; code in any other module may access the types and members in the package.If
exports_to_countis nonzero, then this package is exported by the current module in a qualified fashion; only code in the modules listed in theexports_to_indextable may access the types and members in the package. - exports_to_index[]
-
The value of each entry in the
exports_to_indextable must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Module_infostructure denoting a module whose code can access the types and members in this exported package.For each entry in the
exportstable, at most one entry in itsexports_to_indextable may specify a module of a given name.
- opens_count
-
The value of the
opens_countitem indicates the number of entries in theopenstable. - opens[]
-
Each entry in the
openstable specifies a package opened by the current module, such that all types in the package, and all their members, may be accessed from outside the current module via the reflection libraries of the Java SE Platform, possibly from a limited set of "friend" modules.The items in each entry are as follows:
- opens_index
-
The value of the
opens_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Package_infostructure representing a package opened by the current module.At most one entry in the
openstable may specify a package of a given name with itsopens_indexitem. - opens_flags
- opens_to_count
-
The value of the
opens_to_countindicates the number of entries in theopens_to_indextable.If
opens_to_countis zero, then this package is opened by the current module in an unqualified fashion; code in any other module may reflectively access the types and members in the package.If
opens_to_countis nonzero, then this package is opened by the current module in a qualified fashion; only code in the modules listed in theexports_to_indextable may reflectively access the types and members in the package. - opens_to_index[]
-
The value of each entry in the
opens_to_indextable must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Module_infostructure denoting a module whose code can access the types and members in this opened package.For each entry in the
openstable, at most one entry in itsopens_to_indextable may specify a module of a given name.
- uses_count
-
The value of the
uses_countitem indicates the number of entries in theuses_indextable. - uses_index[]
-
The value of each entry in the
uses_indextable must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Class_infostructure representing a service interface which the current module may discover viajava.util.ServiceLoader.At most one entry in the
uses_indextable may specify a service interface of a given name. - provides_count
-
The value of the
provides_countitem indicates the number of entries in theprovidestable. - provides[]
-
Each entry in the
providestable represents a service implementation for a given service interface.The items in each entry are as follows:
- provides_index
-
The value of the
provides_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Class_infostructure representing a service interface for which the current module provides a service implementation.At most one entry in the
providestable may specify a service interface of a given name with itsprovides_indexitem. - provides_with_count
-
The value of the
provides_with_countindicates the number of entries in theprovides_with_indextable. - provides_with_index[]
-
The value of each entry in the
provides_with_indextable must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Class_infostructure representing a service implementation for the service interface specified byprovides_index.For each entry in the
providestable, at most one entry in itsprovides_with_indextable may specify a service implementation of a given name.
The ModulePackages attribute is a variable-length attribute in the attributes table of a ClassFile structure. The ModulePackages attribute indicates all the packages of a module that are exported or opened by the Module attribute, as well as all the packages of the service implementations recorded in the Module attribute. The ModulePackages attribute may also indicate packages in the module that are neither exported nor opened nor contain service implementations.
There may be at most one ModulePackages attribute in the attributes table of a ClassFile structure.
The ModulePackages attribute has the following format:
ModulePackages_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 package_count;
u2 package_index[package_count];
}
The items of the ModulePackages_attribute structure are as follows:
- attribute_name_index
-
The value of the
attribute_name_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Utf8_infostructure representing the string "ModulePackages". - attribute_length
-
The value of the
attribute_lengthitem is the length of the attribute excluding the initial six bytes. - package_count
-
The value of the
package_countitem indicates the number of entries in thepackage_indextable. - package_index[]
-
The value of each entry in the
package_indextable must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Package_infostructure representing a package in the current module.At most one entry in the
package_indextable may specify a package of a given name.
The ModuleMainClass attribute is a fixed-length attribute in the attributes table of a ClassFile structure. The ModuleMainClass attribute indicates the main class of a module.
There may be at most one ModuleMainClass attribute in the attributes table of a ClassFile structure.
The ModuleMainClass attribute has the following format:
ModuleMainClass_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 main_class_index;
}
The items of the ModuleMainClass_attribute structure are as follows:
- attribute_name_index
-
The value of the
attribute_name_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Utf8_infostructure representing the string "ModuleMainClass". - attribute_length
-
The value of the
attribute_lengthitem is the length of the attribute excluding the initial six bytes. - main_class_index
-
The value of the
main_class_indexitem must be a valid index into theconstant_pooltable. Theconstant_poolentry at that index must be aCONSTANT_Class_infostructure representing the binary name of the main class of the current module.
When a prospective class file is loaded by the Java Virtual Machine (§5.3), the Java Virtual Machine first ensures that the file has the basic format of a class file (§4.1). This process is known as format checking. The checks are as follows:
-
All predefined attributes (§4.7) must be of the proper length, except for
StackMapTable,RuntimeVisibleAnnotations,RuntimeInvisibleAnnotations,RuntimeVisibleParameterAnnotations,RuntimeInvisibleParameterAnnotations,RuntimeVisibleTypeAnnotations,RuntimeInvisibleTypeAnnotations, andAnnotationDefault. -
The
classfile must not be truncated or have extra bytes at the end. -
The constant pool must satisfy the constraints documented throughout §4.4.
For example, each
CONSTANT_Class_infostructure in the constant pool must contain in itsname_indexitem a valid constant pool index for aCONSTANT_Utf8_infostructure. -
All field references and method references in the constant pool must have valid names, valid classes, and valid descriptors (§4.3).
Format checking does not ensure that the given field or method actually exists in the given class, nor that the descriptors given refer to real classes. Format checking ensures only that these items are well formed. More detailed checking is performed when the bytecodes themselves are verified, and during resolution.
These checks for basic class file integrity are necessary for any interpretation of the class file contents. Format checking is distinct from bytecode verification, although historically they have been confused because both are a form of integrity check.
The code for a method, instance initialization method (§2.9.1), or class or interface initialization method (§2.9.2) is stored in the code array of the Code attribute of a method_info structure of a class file (§4.7.3). This section describes the constraints associated with the contents of the Code_attribute structure.
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 theclass 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:
-
Only instances of the instructions documented in §6.5 may appear in the
codearray. Instances of instructions using the reserved opcodes (§6.2) or any opcodes not documented in this specification must not appear in thecodearray.If the
classfile version number is 51.0 or above, then neither the jsr opcode or the jsr_w opcode may appear in thecodearray. -
The opcode of the first instruction in the
codearray begins at index0. -
For each instruction in the
codearray except the last, the index of the opcode of the next instruction equals the index of the opcode of the current instruction plus the length of that instruction, including all its operands.The wide instruction is treated like any other instruction for these purposes; the opcode specifying the operation that a wide instruction is to modify is treated as one of the operands of that wideinstruction. That opcode must never be directly reachable by the computation.
-
The last byte of the last instruction in the
codearray must be the byte at indexcode_length - 1.
The static constraints on the operands of instructions in the code array are as follows:
-
The target of each jump and branch instruction (jsr, jsr_w, goto, goto_w, ifeq, ifne, ifle, iflt, ifge, ifgt, ifnull, ifnonnull, if_icmpeq, if_icmpne, if_icmple, if_icmplt, if_icmpge, if_icmpgt, if_acmpeq,if_acmpne) must be the opcode of an instruction within this method.
The target of a jump or branch instruction must never be the opcode used to specify the operation to be modified by a wide instruction; a jump or branch target may be the wide instruction itself.
-
Each target, including the default, of each tableswitch instruction must be the opcode of an instruction within this method.
Each tableswitch instruction must have a number of entries in its jump table that is consistent with the value of its low and high jump table operands, and its low value must be less than or equal to its high value.
No target of a tableswitch instruction may be the opcode used to specify the operation to be modified by a wide instruction; a tableswitch target may be a wide instruction itself.
-
Each target, including the default, of each lookupswitch instruction must be the opcode of an instruction within this method.
Each lookupswitch instruction must have a number of match-offset pairs that is consistent with the value of its npairs operand. The match-offset pairs must be sorted in increasing numerical order by signed match value.
No target of a lookupswitch instruction may be the opcode used to specify the operation to be modified by a wide instruction; a lookupswitch target may be a wide instruction itself.
-
The operand of each ldc instruction and each ldc_w instruction must be a valid index into the
constant_pooltable. The constant pool entry referenced by that index must be of type:-
CONSTANT_Integer,CONSTANT_Float, orCONSTANT_Stringif theclassfile version number is less than 49.0. -
CONSTANT_Integer,CONSTANT_Float,CONSTANT_String, orCONSTANT_Classif theclassfile version number is 49.0 or 50.0. -
CONSTANT_Integer,CONSTANT_Float,CONSTANT_String,CONSTANT_Class,CONSTANT_MethodType, orCONSTANT_MethodHandleif theclassfile version number is 51.0 or above.
-
-
The operands of each ldc2_w instruction must represent a valid index into the
constant_pooltable. The constant pool entry referenced by that index must be of typeCONSTANT_LongorCONSTANT_Double.The subsequent constant pool index must also be a valid index into the constant pool, and the constant pool entry at that index must not be used.
-
The operands of each getfield, putfield, getstatic, and putstatic instruction must represent a valid index into the
constant_pooltable. The constant pool entry referenced by that index must be of typeCONSTANT_Fieldref. -
The indexbyte operands of each invokevirtual instruction must represent a valid index into the
constant_pooltable. The constant pool entry referenced by that index must be of typeCONSTANT_Methodref. -
The indexbyte operands of each invokespecial and invokestatic instruction must represent a valid index into the
constant_pooltable. If theclassfile version number is less than 52.0, the constant pool entry referenced by that index must be of typeCONSTANT_Methodref; if theclassfile version number is 52.0 or above, the constant pool entry referenced by that index must be of typeCONSTANT_MethodreforCONSTANT_InterfaceMethodref. -
The indexbyte operands of each invokeinterface instruction must represent a valid index into the
constant_pooltable. The constant pool entry referenced by that index must be of typeCONSTANT_InterfaceMethodref.The value of the count operand of each invokeinterface instruction must reflect the number of local variables necessary to store the arguments to be passed to the interface method, as implied by the descriptor of the
CONSTANT_NameAndType_infostructure referenced by theCONSTANT_InterfaceMethodrefconstant pool entry.The fourth operand byte of each invokeinterface instruction must have the value zero.
-
The indexbyte operands of each invokedynamic instruction must represent a valid index into the
constant_pooltable. The constant pool entry referenced by that index must be of typeCONSTANT_InvokeDynamic.The third and fourth operand bytes of each invokedynamic instruction must have the value zero.
-
Only the invokespecial instruction is allowed to invoke an instance initialization method (§2.9.1).
No other method whose name begins with the character '
<' ('u003c') may be called by the method invocation instructions. In particular, the class or interface initialization method specially named<clinit>is never called explicitly from Java Virtual Machine instructions, but only implicitly by the Java Virtual Machine itself. -
The operands of each instanceof, checkcast, new, and anewarray instruction, and the indexbyte operands of each multianewarray instruction, must represent a valid index into the
constant_pooltable. The constant pool entry referenced by that index must be of typeCONSTANT_Class. -
No new instruction may reference a constant pool entry of type
CONSTANT_Classthat represents an array type (§4.3.2). The new instruction cannot be used to create an array. -
No anewarray instruction may be used to create an array of more than 255 dimensions.
-
A multianewarray instruction must be used only to create an array of a type that has at least as many dimensions as the value of its dimensions operand. That is, while a multianewarrayinstruction is not required to create all of the dimensions of the array type referenced by its indexbyte operands, it must not attempt to create more dimensions than are in the array type.
The dimensions operand of each multianewarray instruction must not be zero.
-
The atype operand of each newarray instruction must take one of the values
T_BOOLEAN(4),T_CHAR(5),T_FLOAT(6),T_DOUBLE(7),T_BYTE(8),T_SHORT(9),T_INT(10), orT_LONG(11). -
The index operand of each iload, fload, aload, istore, fstore, astore, iinc, and ret instruction must be a non-negative integer no greater than
max_locals - 1.The implicit index of each iload_<n>, fload_<n>, aload_<n>, istore_<n>, fstore_<n>, and astore_<n> instruction must be no greater than
max_locals - 1. -
The index operand of each lload, dload, lstore, and dstore instruction must be no greater than
max_locals - 2.The implicit index of each lload_<n>, dload_<n>, lstore_<n>, and dstore_<n> instruction must be no greater than
max_locals - 2. -
The indexbyte operands of each wide instruction modifying an iload, fload, aload, istore, fstore, astore, iinc, or ret instruction must represent a non-negative integer no greater than
max_locals - 1.The indexbyte operands of each wide instruction modifying an lload, dload, lstore, or dstore instruction must represent a non-negative integer no greater than
max_locals - 2.
The structural constraints on the code array specify constraints on relationships between Java Virtual Machine instructions. The structural constraints are as follows:
-
Each instruction must only be executed with the appropriate type and number of arguments in the operand stack and local variable array, regardless of the execution path that leads to its invocation.
An instruction operating on values of type
intis also permitted to operate on values of typeboolean,byte,char, andshort.As noted in §2.3.4 and §2.11.1, the Java Virtual Machine internally converts values of types
boolean,byte,short, andcharto typeint.) -
If an instruction can be executed along several different execution paths, the operand stack must have the same depth (§2.6.2) prior to the execution of the instruction, regardless of the path taken.
-
At no point during execution can the operand stack grow to a depth greater than that implied by the
max_stackitem. -
At no point during execution can more values be popped from the operand stack than it contains.
-
At no point during execution can the order of the local variable pair holding a value of type
longordoublebe reversed or the pair split up. At no point can the local variables of such a pair be operated on individually. -
No local variable (or local variable pair, in the case of a value of type
longordouble) can be accessed before it is assigned a value. -
Each invokespecial instruction must name one of the following:
-
an instance initialization method (§2.9.1)
-
a method in a direct superinterface of the current class or interface
If an invokespecial instruction names an instance initialization method, then the target reference on the operand stack must be an uninitialized class instance. An instance initialization method must never be invoked on an initialized class instance. In addition:
-
If the target reference on the operand stack is an uninitialized class instance for the current class, then invokespecial must name an instance initialization method from the current class or its direct superclass.
-
If an invokespecial instruction names an instance initialization method and the target reference on the operand stack is a class instance created by an earlier new instruction, theninvokespecial must name an instance initialization method from the class of that class instance.
If an invokespecial instruction names a method which is not an instance initialization method, then the target reference on the operand stack must be a class instance whose type is assignment compatible with the current class (JLS §5.2).
The general rule for invokespecial is that the class or interface named by invokespecial must be be "above" the caller class or interface, while the receiver object targeted by invokespecial must be "at" or "below" the caller class or interface. The latter clause is especially important: a class or interface can only perform invokespecial on its own objects. See §invokespecial for an explanation of how the latter clause is implemented in Prolog.
-
-
Each instance initialization method, except for the instance initialization method derived from the constructor of class
Object, must call either another instance initialization method ofthisor an instance initialization method of its direct superclasssuperbefore its instance members are accessed.However, instance fields of
thisthat are declared in the current class may be assigned by putfield before calling any instance initialization method. -
When any instance method is invoked or when any instance variable is accessed, the class instance that contains the instance method or instance variable must already be initialized.
-
If there is an uninitialized class instance in a local variable in code protected by an exception handler, then i) if the handler is inside an
<init>method, the handler must throw an exception or loop forever, and ii) if the handler is not inside an<init>method, the uninitialized class instance must remain uninitialized. -
There must never be an uninitialized class instance on the operand stack or in a local variable when a jsr or jsr_w instruction is executed.
-
The type of every class instance that is the target of a method invocation instruction (that is, the type of the target reference on the operand stack) must be assignment compatible with the class or interface type specified in the instruction.
-
The types of the arguments to each method invocation must be method invocation compatible with the method descriptor (JLS §5.3, §4.3.3).
-
Each return instruction must match its method's return type:
-
If the method returns a
boolean,byte,char,short, orint, only the ireturn instruction may be used. -
If the method returns a
float,long, ordouble, only an freturn, lreturn, or dreturn instruction, respectively, may be used. -
If the method returns a
referencetype, only an areturn instruction may be used, and the type of the returned value must be assignment compatible with the return descriptor of the method (§4.3.3). -
All instance initialization methods, class or interface initialization methods, and methods declared to return
voidmust use only the return instruction.
-
-
The type of every class instance accessed by a getfield instruction or modified by a putfield instruction (that is, the type of the target reference on the operand stack) must be assignment compatible with the class type specified in the instruction.
-
The type of every value stored by a putfield or putstatic instruction must be compatible with the descriptor of the field (§4.3.2) of the class instance or class being stored into:
-
If the descriptor type is
boolean,byte,char,short, orint, then the value must be anint. -
If the descriptor type is
float,long, ordouble, then the value must be afloat,long, ordouble, respectively. -
If the descriptor type is a
referencetype, then the value must be of a type that is assignment compatible with the descriptor type.
-
-
The type of every value stored into an array by an aastore instruction must be a
referencetype.The component type of the array being stored into by the aastore instruction must also be a
referencetype. -
Each athrow instruction must throw only values that are instances of class
Throwableor of subclasses ofThrowable.Each class mentioned in a
catch_typeitem of theexception_tablearray of the method'sCode_attributestructure must beThrowableor a subclass ofThrowable. -
If getfield or putfield is used to access a
protectedfield declared in a superclass that is a member of a different run-time package than the current class, then the type of the class instance being accessed (that is, the type of the target reference on the operand stack) must be assignment compatible with the current class.If invokevirtual or invokespecial is used to access a
protectedmethod declared in a superclass that is a member of a different run-time package than the current class, then the type of the class instance being accessed (that is, the type of the target reference on the operand stack) must be assignment compatible with the current class. -
No return address (a value of type
returnAddress) may be loaded from a local variable. -
The instruction following each jsr or jsr_w instruction may be returned to only by a single ret instruction.
-
No jsr or jsr_w instruction that is returned to may be used to recursively call a subroutine if that subroutine is already present in the subroutine call chain. (Subroutines can be nested when using
try-finallyconstructs from within afinallyclause.) -
Each instance of type
returnAddresscan be returned to at most once.If a ret instruction returns to a point in the subroutine call chain above the ret instruction corresponding to a given instance of type
returnAddress, then that instance can never be used as a return address.
Even though a compiler for the Java programming language must only produce class files that satisfy all the static and structural constraints in the previous sections, the Java Virtual Machine has no guarantee that any file it is asked to load was generated by that compiler or is properly formed. Applications such as web browsers do not download source code, which they then compile; these applications download already-compiled class files. The browser needs to determine whether the class file was produced by a trustworthy compiler or by an adversary attempting to exploit the Java Virtual Machine.
An additional problem with compile-time checking is version skew. A user may have successfully compiled a class, say PurchaseStockOptions, to be a subclass of TradingClass. But the definition of TradingClass might have changed since the time the class was compiled in a way that is not compatible with pre-existing binaries. Methods might have been deleted or had their return types or modifiers changed. Fields might have changed types or changed from instance variables to class variables. The access modifiers of a method or variable may have changed from public to private. For a discussion of these issues, see Chapter 13, "Binary Compatibility," in The Java Language Specification, Java SE 9 Edition.
Because of these potential problems, the Java Virtual Machine needs to verify for itself that the desired constraints are satisfied by the class files it attempts to incorporate. A Java Virtual Machine implementation verifies that each class file satisfies the necessary constraints at linking time (§5.4).
Link-time verification enhances the performance of the run-time interpreter. Expensive checks that would otherwise have to be performed to verify constraints at run time for each interpreted instruction can be eliminated. The Java Virtual Machine can assume that these checks have already been performed. For example, the Java Virtual Machine will already know the following:
There are two strategies that Java Virtual Machine implementations may use for verification:
-
Verification by type checking must be used to verify
classfiles whose version number is greater than or equal to 50.0. -
Verification by type inference must be supported by all Java Virtual Machine implementations, except those conforming to the Java ME CLDC and Java Card profiles, in order to verify
classfiles whose version number is less than 50.0.Verification on Java Virtual Machine implementations supporting the Java ME CLDC and Java Card profiles is governed by their respective specifications.
In both strategies, verification is mainly concerned with enforcing the static and structural constraints from §4.9 on the code array of the Code attribute (§4.7.3). However, there are three additional checks outside the Code attribute which must be performed during verification:
-
Ensuring that
finalmethods are not overridden (§5.4.5). -
Checking that every class (except
Object) has a direct superclass.
A class file whose version number is 50.0 or above (§4.1) must be verified using the type checking rules given in this section.
If, and only if, a class file's version number equals 50.0, then if the type checking fails, a Java Virtual Machine implementation may choose to attempt to perform verification by type inference (§4.10.2).
This is a pragmatic adjustment, designed to ease the transition to the new verification discipline. Many tools that manipulate class files may alter the bytecodes of a method in a manner that requires adjustment of the method's stack map frames. If a tool does not make the necessary adjustments to the stack map frames, type checking may fail even though the bytecode is in principle valid (and would consequently verify under the old type inference scheme). To allow implementors time to adapt their tools, Java Virtual Machine implementations may fall back to the older verification discipline, but only for a limited time.
In cases where type checking fails but type inference is invoked and succeeds, a certain performance penalty is expected. Such a penalty is unavoidable. It also should serve as a signal to tool vendors that their output needs to be adjusted, and provides vendors with additional incentive to make these adjustments.
In summary, failover to verification by type inference supports both the gradual addition of stack map frames to the Java SE Platform (if they are not present in a version 50.0 class file, failover is allowed) and the gradual removal of the jsr and jsr_w instructions from the Java SE Platform (if they are present in a version 50.0 class file, failover is allowed).
If a Java Virtual Machine implementation ever attempts to perform verification by type inference on version 50.0 class files, it must do so in all cases where verification by type checking fails.
This means that a Java Virtual Machine implementation cannot choose to resort to type inference in once case and not in another. It must either reject class files that do not verify via type checking, or else consistently failover to the type inferencing verifier whenever type checking fails.
The type checker enforces type rules that are specified by means of Prolog clauses. English language text is used to describe the type rules in an informal way, while the Prolog clauses provide a formal specification.
The type checker requires a list of stack map frames for each method with a Code attribute (§4.7.3). A list of stack map frames is given by the StackMapTable attribute (§4.7.4) of a Codeattribute. The intent is that a stack map frame must appear at the beginning of each basic block in a method. The stack map frame specifies the verification type of each operand stack entry and of each local variable at the start of each basic block. The type checker reads the stack map frames for each method with a Code attribute and uses these maps to generate a proof of the type safety of the instructions in the Code attribute.
A class is type safe if all its methods are type safe, and it does not subclass a final class.
classIsTypeSafe(Class) :-
classClassName(Class, Name),
classDefiningLoader(Class, L),
superclassChain(Name, L, Chain),
Chain = [],
classSuperClassName(Class, SuperclassName),
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).
The Prolog predicate classIsTypeSafe assumes that Class is a Prolog term representing a binary class that has been successfully parsed and loaded. This specification does not mandate the precise structure of this term, but does require that certain predicates be defined upon it.
For example, we assume a predicate classMethods(Class, Methods) that, given a term representing a class as described above as its first argument, binds its second argument to a list comprising all the methods of the class, represented in a convenient form described later.
Iff the predicate classIsTypeSafe is not true, the type checker must throw the exception VerifyError to indicate that the class file is malformed. Otherwise, the class file has type checked successfully and bytecode verification has completed successfully.
The rest of this section explains the process of type checking in detail:
-
First, we give Prolog predicates for core Java Virtual Machine artifacts like classes and methods (§4.10.1.1).
-
Second, we specify the type system known to the type checker (§4.10.1.2).
-
Third, we specify the Prolog representation of instructions and stack map frames (§4.10.1.3, §4.10.1.4).
-
Fourth, we specify how a method is type checked, for methods without code (§4.10.1.5) and methods with code (§4.10.1.6).
-
Fifth, we discuss type checking issues common to all load and store instructions (§4.10.1.7), and also issues of access to
protectedmembers (§4.10.1.8). -
Finally, we specify the rules to type check each instruction (§4.10.1.9).
We stipulate the existence of 28 Prolog predicates ("accessors") that have certain expected behavior but whose formal definitions are not given in this specification.
- classClassName(Class, ClassName)
- classIsInterface(Class)
- classIsNotFinal(Class)
- classSuperClassName(Class, SuperClassName)
-
Extracts the name,
SuperClassName, of the superclass of classClass. - classInterfaces(Class, Interfaces)
-
Extracts a list,
Interfaces, of the direct superinterfaces of the classClass. - classMethods(Class, Methods)
-
Extracts a list,
Methods, of the methods declared in the classClass. - classAttributes(Class, Attributes)
-
Extracts a list,
Attributes, of the attributes of the classClass.Each attribute is represented as a functor application of the form
attribute(AttributeName, AttributeContents), whereAttributeNameis the name of the attribute. The format of the attribute's contents is unspecified. - classDefiningLoader(Class, Loader)
-
Extracts the defining class loader,
Loader, of the classClass. - isBootstrapLoader(Loader)
-
True iff the class loader
Loaderis the bootstrap class loader. - loadedClass(Name, InitiatingLoader, ClassDefinition)
-
True iff there exists a class named
Namewhose representation (in accordance with this specification) when loaded by the class loaderInitiatingLoaderisClassDefinition. - methodName(Method, Name)
- methodAccessFlags(Method, AccessFlags)
-
Extracts the access flags,
AccessFlags, of the methodMethod. - methodDescriptor(Method, Descriptor)
- methodAttributes(Method, Attributes)
-
Extracts a list,
Attributes, of the attributes of the methodMethod. - isInit(Method)
- isNotInit(Method)
- isNotFinal(Method, Class)
- isStatic(Method, Class)
- isNotStatic(Method, Class)
- isPrivate(Method, Class)
- isNotPrivate(Method, Class)
- isProtected(MemberClass, MemberName, MemberDescriptor)
-
True iff there is a member named
MemberNamewith descriptorMemberDescriptorin the classMemberClassand it isprotected. - isNotProtected(MemberClass, MemberName, MemberDescriptor)
-
True iff there is a member named
MemberNamewith descriptorMemberDescriptorin the classMemberClassand it is notprotected. - parseFieldDescriptor(Descriptor, Type)
-
Converts a field descriptor,
Descriptor, into the corresponding verification typeType(§4.10.1.2). - 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. - parseCodeAttribute(Class, Method, FrameSize, MaxStack, ParsedCode, Handlers, StackMap)
-
Extracts the instruction stream,
ParsedCode, of the methodMethodinClass, as well as the maximum operand stack size,MaxStack, the maximal number of local variables,FrameSize, the exception handlers,Handlers, and the stack mapStackMap.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
Class1andClass2are the same. - differentPackageName(Class1, Class2)
-
True iff the package names of
Class1andClass2are different.
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:
-
a class
-
a method
-
the declared return type of the method
-
the instructions in a method
-
the maximal size of the operand stack
-
a list of exception handlers
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).
thisClass(Environment, class(ClassName, L)) :-
Environment = environment(Class, _Method, _ReturnType,
_Instructions, _, _),
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.
The type checker enforces a type system based upon a hierarchy of verification types, illustrated below.
Verification type hierarchy:
top
____________/\____________
/
/
oneWord twoWord
/ | /
/ | /
int float reference long double
/
/ \_____________
/
/
uninitialized +------------------+
/ | Java reference |
/ | type hierarchy |
uninitializedThis uninitialized(Offset) +------------------+
|
|
null
Most verification types have a direct correspondence with the primitive and reference types represented by field descriptors in Table 4.3-A:
-
The primitive types
double,float,int, andlong(field descriptorsD,F,I,J) each correspond to the verification type of the same name. -
The primitive types
byte,char,short, andboolean(field descriptorsB,C,S,Z) all correspond to the verification typeint. -
Class and interface types (field descriptors beginning
L) correspond to verification types that use the functorclass. The verification typeclass(N, L)represents the class whose binary name isNas loaded by the loaderL. Note thatLis an initiating loader (§5.3) of the class represented byclass(N, L)and may, or may not, be the class's defining loader.For example, the class type
Objectwould be represented asclass('java/lang/Object', BL), whereBLis the bootstrap loader. -
Array types (field descriptors beginning
[) correspond to verification types that use the functorarrayOf. Note that the primitive typesbyte,char,short, andbooleando not correspond to verification types, but an array type whose element type isbyte,char,short, orbooleandoes correspond to a verification type; such verification types support the baload, bastore, caload, castore, saload, sastore, and newarray instructions.-
The verification type
arrayOf(T)represents the array type whose component type is the verification typeT. -
The verification type
arrayOf(byte)represents the array type whose element type isbyte. -
The verification type
arrayOf(char)represents the array type whose element type ischar. -
The verification type
arrayOf(short)represents the array type whose element type isshort. -
The verification type
arrayOf(boolean)represents the array type whose element type isboolean.
For example, the array types
int[]andObject[]would be represented by the verification typesarrayOf(int)andarrayOf(class('java/lang/Object', BL))respectively. The array typesbyte[]andboolean[][]would be represented by the verification typesarrayOf(byte)andarrayOf(arrayOf(boolean))respectively. -
The remaining verification types are described as follows:
-
The verification types
top,oneWord,twoWord, andreferenceare represented in Prolog as atoms whose name denotes the verification type in question. -
The verification type
uninitialized(Offset)is represented by applying the functoruninitializedto an argument representing the numerical value of theOffset.
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:
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(reference, X) :- isAssignable(oneWord, X).
isAssignable(class(_, _), 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).
isAssignable(null, class(_, _)).
isAssignable(null, arrayOf(_)).
isAssignable(null, X) :- isAssignable(class('java/lang/Object', BL), X),
isBootstrapLoader(BL).
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, 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 class(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.
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)).
For assignments, interfaces are treated like Object.
isJavaAssignable(class(_, _), class(To, L)) :-
loadedClass(To, L, ToClass),
classIsInterface(ToClass).
isJavaAssignable(From, To) :-
isJavaSubclassOf(From, To).
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).
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.
isJavaAssignable(arrayOf(X), arrayOf(Y)) :-
compound(X), compound(Y), isJavaAssignable(X, Y).
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).
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).
Individual bytecode instructions are represented in Prolog as terms whose functor is the name of the instruction and whose arguments are its parsed operands.
For example, an aload instruction is represented as the term aload(N), which includes the index N that is the operand of the instruction.
The instructions as a whole are represented as a list of terms of the form:
instruction(Offset, AnInstruction)
For example, instruction(21, aload(1)).
The order of instructions in this list must be the same as in the class file.
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_infostructure, 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:
-
field(FieldClassName, FieldName, FieldDescriptor)for a field, whereFieldClassNameis the name of the class referenced by theclass_indexitem in theCONSTANT_Fieldref_infostructure, andFieldNameandFieldDescriptorcorrespond to the name and field descriptor referenced by thename_and_type_indexitem of theCONSTANT_Fieldref_infostructure. -
imethod(MethodIntfName, MethodName, MethodDescriptor)for an interface's method, whereMethodIntfNameis the name of the interface referenced by theclass_indexitem of theCONSTANT_InterfaceMethodref_infostructure, andMethodNameandMethodDescriptorcorrespond to the name and method descriptor referenced by thename_and_type_indexitem of theCONSTANT_InterfaceMethodref_infostructure; -
method(MethodClassName, MethodName, MethodDescriptor)for a class's method, whereMethodClassNameis the name of the class referenced by theclass_indexitem of theCONSTANT_Methodref_infostructure, andMethodNameandMethodDescriptorcorrespond to the name and method descriptor referenced by thename_and_type_indexitem of theCONSTANT_Methodref_infostructure; and -
dmethod(CallSiteName, MethodDescriptor)for a dynamic call site, whereCallSiteNameandMethodDescriptorcorrespond to the name and method descriptor referenced by thename_and_type_indexitem of theCONSTANT_InvokeDynamic_infostructure.
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 BaseTypecharacters used for primitive types are mapped to the names of those types.
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 Bar would be represented as getfield(field('Bar', 'foo', 'F')).
Constant pool entries that refer to constant values, such as CONSTANT_String, CONSTANT_Integer, CONSTANT_Float, CONSTANT_Long, CONSTANT_Double, and CONSTANT_Class, are encoded via the functors whose names are string, int, float, long, double, and classConstant respectively.
For example, an ldc instruction for loading the integer 91 would be encoded as ldc(int(91)).
Stack map frames are represented in Prolog as a list of terms of the form:
stackMap(Offset, TypeState)
-
Offsetis an integer indicating the bytecode offset at which the stack map frame applies (§4.7.4).The order of bytecode offsets in this list must be the same as in the
classfile. -
TypeStateis the expected incoming type state for the instruction atOffset.
A type state is a mapping from locations in the operand stack and local variables of a method to verification types. It has the form:
frame(Locals, OperandStack, Flags)
-
Localsis a list of verification types, such that the i'th element of the list (with 0-based indexing) represents the type of local variable i.Types of size 2 (
longanddouble) are represented by two local variables (§2.6.1), with the first local variable being the type itself and the second local variable beingtop(§4.10.1.7). -
OperandStackis a list of verification types, such that the first element of the list represents the type of the top of the operand stack, and the types of stack entries below the top follow in the list in the appropriate order.Types of size 2 (
longanddouble) are represented by two stack entries, with the first entry beingtopand the second entry being the type itself.For example, a stack with a
doublevalue, anintvalue, and alongvalue is represented in a type state as a stack with five entries:topanddoubleentries for thedoublevalue, anintentry for theintvalue, andtopandlongentries for thelongvalue. Accordingly,OperandStackis the list[top, double, int, top, long]. -
Flagsis a list which may either be empty or have the single elementflagThisUninit.If any local variable in
Localshas the typeuninitializedThis, thenFlagshas the single elementflagThisUninit, otherwiseFlagsis an empty list.flagThisUninitis used in constructors to mark type states where initialization ofthishas not yet been completed. In such type states, it is illegal to return from the method.
Subtyping of verification types is extended pointwise to type states. The local variable array of a method has a fixed length by construction (see methodInitialStackFrame in §4.10.1.6), but the operand stack grows and shrinks, so we require an explicit check on the length of the operand stacks whose assignability is desired for subtyping.
frameIsAssignable(frame(Locals1, StackMap1, Flags1),
frame(Locals2, StackMap2, Flags2)) :-
length(StackMap1, StackMapLength),
length(StackMap2, StackMapLength),
maplist(isAssignable, Locals1, Locals2),
maplist(isAssignable, StackMap1, StackMap2),
subset(Flags1, Flags2).
Most of the type rules for individual instructions (§4.10.1.9) depend on the notion of a valid type transition. A type transition is valid if one can pop a list of expected types off the incoming type state's operand stack and replace them with an expected result type, resulting in a new type state where the length of the operand stack does not exceed its declared maximum size.
validTypeTransition(Environment, ExpectedTypesOnStack, ResultType,
frame(Locals, InputOperandStack, Flags),
frame(Locals, NextOperandStack, Flags)) :-
popMatchingList(InputOperandStack, ExpectedTypesOnStack,
InterimOperandStack),
pushOperandStack(InterimOperandStack, ResultType, NextOperandStack),
operandStackHasLegalLength(Environment, NextOperandStack).
Pop a list of types off the stack.
popMatchingList(OperandStack, [], OperandStack).
popMatchingList(OperandStack, [P | Rest], NewOperandStack) :-
popMatchingType(OperandStack, P, TempOperandStack, _ActualType),
popMatchingList(TempOperandStack, Rest, NewOperandStack).
Pop an individual type off the stack. The exact behavior depends on the stack contents. If the logical top of the stack is some subtype of the specified type, Type, then pop it. If a type occupies two stack entries, then the logical top of the stack is really the type just below the top, and the top of the stack is the unusable type top.
popMatchingType([ActualType | OperandStack],
Type, OperandStack, ActualType) :-
sizeOf(Type, 1),
isAssignable(ActualType, Type).
popMatchingType([top, ActualType | OperandStack],
Type, OperandStack, ActualType) :-
sizeOf(Type, 2),
isAssignable(ActualType, Type).
sizeOf(X, 2) :- isAssignable(X, twoWord).
sizeOf(X, 1) :- isAssignable(X, oneWord).
sizeOf(top, 1).
Push a logical type onto the stack. The exact behavior varies with the size of the type. If the pushed type is of size 1, we just push it onto the stack. If the pushed type is of size 2, we push it, and then push top.
pushOperandStack(OperandStack, 'void', OperandStack).
pushOperandStack(OperandStack, Type, [Type | OperandStack]) :-
sizeOf(Type, 1).
pushOperandStack(OperandStack, Type, [top, Type | OperandStack]) :-
sizeOf(Type, 2).
The length of the operand stack must not exceed the declared maximum size.
operandStackHasLegalLength(Environment, OperandStack) :-
length(OperandStack, Length),
maxOperandStackLength(Environment, MaxStack),
Length =< MaxStack.
The dup instructions pop expected types off the incoming type state's operand stack and replace them with predefined result types, resulting in a new type state. However, these instructions are not defined in terms of type transitions because there is no need to match types by means of the subtyping relation. Instead, the dup instructions manipulate the operand stack entirely in terms of the category of types on the stack (§2.11.1).
Category 1 types occupy a single stack entry. Popping a logical type of category 1, Type, off the stack is possible if the top of the stack is Type and Type is not top (otherwise it could denote the upper half of a category 2 type). The result is the incoming stack, with the top entry popped off.
popCategory1([Type | Rest], Type, Rest) :-
Type = top,
sizeOf(Type, 1).
Category 2 types occupy two stack entries. Popping a logical type of category 2, Type, off the stack is possible if the top of the stack is type top, and the entry directly below it is Type. The result is the incoming stack, with the top two entries popped off.
popCategory2([top, Type | Rest], Type, Rest) :-
sizeOf(Type, 2).
The dup instructions push a list of types onto the stack in essentially the same way as when a type is pushed for a valid type transition.
canSafelyPush(Environment, InputOperandStack, Type, OutputOperandStack) :-
pushOperandStack(InputOperandStack, Type, OutputOperandStack),
operandStackHasLegalLength(Environment, OutputOperandStack).
canSafelyPushList(Environment, InputOperandStack, Types,
OutputOperandStack) :-
canPushList(InputOperandStack, Types, OutputOperandStack),
operandStackHasLegalLength(Environment, OutputOperandStack).
canPushList(InputOperandStack, [], InputOperandStack).
canPushList(InputOperandStack, [Type | Rest], OutputOperandStack) :-
pushOperandStack(InputOperandStack, Type, InterimOperandStack),
canPushList(InterimOperandStack, Rest, OutputOperandStack).
Many of the type rules for individual instructions use the following clause to easily pop a list of types off the stack.
canPop(frame(Locals, OperandStack, Flags), Types,
frame(Locals, PoppedOperandStack, Flags)) :-
popMatchingList(OperandStack, Types, PoppedOperandStack).
Finally, certain array instructions (§aaload, §arraylength, §baload, §bastore) peek at types on the operand stack in order to check they are array types. The following clause accesses the i'th element of the operand stack from a type state.
nth1OperandStackIs(i, frame(_Locals, OperandStack, _Flags), Element) :-
nth1(i, OperandStack, Element).
abstract methods and native methods are considered to be type safe if they do not override a final method.
methodIsTypeSafe(Class, Method) :-
doesNotOverrideFinalMethod(Class, Method),
methodAccessFlags(Method, AccessFlags),
member(abstract, AccessFlags).
methodIsTypeSafe(Class, Method) :-
doesNotOverrideFinalMethod(Class, Method),
methodAccessFlags(Method, AccessFlags),
member(native, AccessFlags).
private methods and static methods are orthogonal to dynamic method dispatch, so they never override other methods (§5.4.5).
doesNotOverrideFinalMethod(class('java/lang/Object', L), Method) :-
isBootstrapLoader(L).
doesNotOverrideFinalMethod(Class, Method) :-
isPrivate(Method, Class).
doesNotOverrideFinalMethod(Class, Method) :-
isStatic(Method, Class).
doesNotOverrideFinalMethod(Class, Method) :-
isNotPrivate(Method, Class),
isNotStatic(Method, Class),
doesNotOverrideFinalMethodOfSuperclass(Class, Method).
doesNotOverrideFinalMethodOfSuperclass(Class, Method) :-
classSuperClassName(Class, SuperclassName),
classDefiningLoader(Class, L),
loadedClass(SuperclassName, L, Superclass),
classMethods(Superclass, SuperMethodList),
finalMethodNotOverridden(Method, Superclass, SuperMethodList).
final methods that are private and/or static are unusual, as private methods and static methods cannot be overridden per se. Therefore, if a final private method or a finalstatic method is found, it was logically not overridden by another method.
finalMethodNotOverridden(Method, Superclass, SuperMethodList) :-
methodName(Method, Name),
methodDescriptor(Method, Descriptor),
member(method(_, Name, Descriptor), SuperMethodList),
isFinal(Method, Superclass),
isPrivate(Method, Superclass).
finalMethodNotOverridden(Method, Superclass, SuperMethodList) :-
methodName(Method, Name),
methodDescriptor(Method, Descriptor),
member(method(_, Name, Descriptor), SuperMethodList),
isFinal(Method, Superclass),
isStatic(Method, Superclass).
If a non-final private method or a non-final static method is found, skip over it because it is orthogonal to overriding.
finalMethodNotOverridden(Method, Superclass, SuperMethodList) :-
methodName(Method, Name),
methodDescriptor(Method, Descriptor),
member(method(_, Name, Descriptor), SuperMethodList),
isNotFinal(Method, Superclass),
isPrivate(Method, Superclass),
doesNotOverrideFinalMethodOfSuperclass(Superclass, Method).
finalMethodNotOverridden(Method, Superclass, SuperMethodList) :-
methodName(Method, Name),
methodDescriptor(Method, Descriptor),
member(method(_, Name, Descriptor), SuperMethodList),
isNotFinal(Method, Superclass),
isStatic(Method, Superclass),
doesNotOverrideFinalMethodOfSuperclass(Superclass, Method).
If a non-final, non-private, non-static method is found, then indeed a final method was not overridden. Otherwise, recurse upwards.
finalMethodNotOverridden(Method, Superclass, SuperMethodList) :-
methodName(Method, Name),
methodDescriptor(Method, Descriptor),
member(method(_, Name, Descriptor), SuperMethodList),
isNotFinal(Method, Superclass),
isNotStatic(Method, Superclass),
isNotPrivate(Method, Superclass).
finalMethodNotOverridden(Method, Superclass, SuperMethodList) :-
methodName(Method, Name),
methodDescriptor(Method, Descriptor),
notMember(method(_, Name, Descriptor), SuperMethodList),
doesNotOverrideFinalMethodOfSuperclass(Superclass, Method).
Non-abstract, non-native methods are type correct if they have code and the code is type correct.
methodIsTypeSafe(Class, Method) :-
doesNotOverrideFinalMethod(Class, Method),
methodAccessFlags(Method, AccessFlags),
methodAttributes(Method, Attributes),
notMember(native, AccessFlags),
notMember(abstract, AccessFlags),
member(attribute('Code', _), Attributes),
methodWithCodeIsTypeSafe(Class, Method).
A method with code is type safe if it is possible to merge the code and the stack map frames into a single stream such that each stack map frame precedes the instruction it corresponds to, and the merged stream is type correct. The method's exception handlers, if any, must also be legal.
methodWithCodeIsTypeSafe(Class, Method) :-
parseCodeAttribute(Class, Method, FrameSize, MaxStack,
ParsedCode, Handlers, StackMap),
mergeStackMapAndCode(StackMap, ParsedCode, MergedCode),
methodInitialStackFrame(Class, Method, FrameSize, StackFrame, ReturnType),
Environment = environment(Class, Method, ReturnType, MergedCode,
MaxStack, Handlers),
handlersAreLegal(Environment),
mergedCodeIsTypeSafe(Environment, MergedCode, StackFrame).
Let us consider exception handlers first.
An exception handler is represented by a functor application of the form:
handler(Start, End, Target, ClassName)
whose arguments are, respectively, the start and end of the range of instructions covered by the handler, the first instruction of the handler code, and the name of the exception class that this handler is designed to handle.
An exception handler is legal if its start (Start) is less than its end (End), there exists an instruction whose offset is equal to Start, there exists an instruction whose offset equals End, and the handler's exception class is assignable to the class Throwable. The exception class of a handler is Throwable if the handler's class entry is 0, otherwise it is the class named in the handler.
An additional requirement exists for a handler inside an <init> method if one of the instructions covered by the handler is invokespecial of an <init> method. In this case, the fact that a handler is running means the object under construction is likely broken, so it is important that the handler does not swallow the exception and allow the enclosing <init> method to return normally to the caller. Accordingly, the handler is required to either complete abruptly by throwing an exception to the caller of the enclosing <init> method, or to loop forever.
handlersAreLegal(Environment) :-
exceptionHandlers(Environment, Handlers),
checklist(handlerIsLegal(Environment), Handlers).
handlerIsLegal(Environment, Handler) :-
Handler = handler(Start, End, Target, _),
Start < End,
allInstructions(Environment, Instructions),
member(instruction(Start, _), Instructions),
offsetStackFrame(Environment, Target, _),
instructionsIncludeEnd(Instructions, End),
currentClassLoader(Environment, CurrentLoader),
handlerExceptionClass(Handler, ExceptionClass, CurrentLoader),
isBootstrapLoader(BL),
isAssignable(ExceptionClass, class('java/lang/Throwable', BL)),
initHandlerIsLegal(Environment, Handler).
instructionsIncludeEnd(Instructions, End) :-
member(instruction(End, _), Instructions).
instructionsIncludeEnd(Instructions, End) :-
member(endOfCode(End), Instructions).
handlerExceptionClass(handler(_, _, _, 0),
class('java/lang/Throwable', BL), _) :-
isBootstrapLoader(BL).
handlerExceptionClass(handler(_, _, _, Name),
class(Name, L), L) :-
Name = 0.
initHandlerIsLegal(Environment, Handler) :-
notInitHandler(Environment, Handler).
notInitHandler(Environment, Handler) :-
Environment = environment(_Class, Method, _, Instructions, _, _),
isNotInit(Method).
notInitHandler(Environment, Handler) :-
Environment = environment(_Class, Method, _, Instructions, _, _),
isInit(Method),
member(instruction(_, invokespecial(CP)), Instructions),
CP = method(MethodClassName, MethodName, Descriptor),
MethodName = '<init>'.
initHandlerIsLegal(Environment, Handler) :-
isInitHandler(Environment, Handler),
sublist(isApplicableInstruction(Target), Instructions,
HandlerInstructions),
noAttemptToReturnNormally(HandlerInstructions).
isInitHandler(Environment, Handler) :-
Environment = environment(_Class, Method, _, Instructions, _, _),
isInit(Method).
member(instruction(_, invokespecial(CP)), Instructions),
CP = method(MethodClassName, '<init>', Descriptor).
isApplicableInstruction(HandlerStart, instruction(Offset, _)) :-
Offset >= HandlerStart.
noAttemptToReturnNormally(Instructions) :-
notMember(instruction(_, return), Instructions).
noAttemptToReturnNormally(Instructions) :-
member(instruction(_, athrow), Instructions).
Let us now turn to the stream of instructions and stack map frames.
Merging instructions and stack map frames into a single stream involves four cases:
-
Merging an empty
StackMapand a list of instructions yields the original list of instructions.mergeStackMapAndCode([], CodeList, CodeList).
-
Given a list of stack map frames beginning with the type state for the instruction at
Offset, and a list of instructions beginning atOffset, the merged list is the head of the stack map frame list, followed by the head of the instruction list, followed by the merge of the tails of the two lists.mergeStackMapAndCode([stackMap(Offset, Map) | RestMap], [instruction(Offset, Parse) | RestCode], [stackMap(Offset, Map), instruction(Offset, Parse) | RestMerge]) :- mergeStackMapAndCode(RestMap, RestCode, RestMerge). -
Otherwise, given a list of stack map frames beginning with the type state for the instruction at
OffsetM, and a list of instructions beginning atOffsetP, then, ifOffsetP < OffsetM, the merged list consists of the head of the instruction list, followed by the merge of the stack map frame list and the tail of the instruction list.mergeStackMapAndCode([stackMap(OffsetM, Map) | RestMap], [instruction(OffsetP, Parse) | RestCode], [instruction(OffsetP, Parse) | RestMerge]) :- OffsetP < OffsetM, mergeStackMapAndCode([stackMap(OffsetM, Map) | RestMap], RestCode, RestMerge). -
Otherwise, the merge of the two lists is undefined. Since the instruction list has monotonically increasing offsets, the merge of the two lists is not defined unless every stack map frame offset has a corresponding instruction offset and the stack map frames are in monotonically increasing order.
To determine if the merged stream for a method is type correct, we first infer the method's initial type state.
The initial type state of a method consists of an empty operand stack and local variable types derived from the type of this and the arguments, as well as the appropriate flag, depending on whether this is an <init> method.
methodInitialStackFrame(Class, Method, FrameSize, frame(Locals, [], Flags),
ReturnType):-
methodDescriptor(Method, Descriptor),
parseMethodDescriptor(Descriptor, RawArgs, ReturnType),
expandTypeList(RawArgs, Args),
methodInitialThisType(Class, Method, ThisList),
flags(ThisList, Flags),
append(ThisList, Args, ThisArgs),
expandToLength(ThisArgs, FrameSize, top, Locals).
Given a list of types, the following clause produces a list where every type of size 2 has been substituted by two entries: one for itself, and one top entry. The result then corresponds to the representation of the list as 32-bit words in the Java Virtual Machine.
expandTypeList([], []).
expandTypeList([Item | List], [Item | Result]) :-
sizeOf(Item, 1),
expandTypeList(List, Result).
expandTypeList([Item | List], [Item, top | Result]) :-
sizeOf(Item, 2),
expandTypeList(List, Result).
flags([uninitializedThis], [flagThisUninit]).
flags(X, []) :- X = [uninitializedThis].
expandToLength(List, Size, _Filler, List) :-
length(List, Size).
expandToLength(List, Size, Filler, Result) :-
length(List, ListLength),
ListLength < Size,
Delta is Size - ListLength,
length(Extra, Delta),
checklist(=(Filler), Extra),
append(List, Extra, Result).
For the initial type state of an instance method, we compute the type of this and put it in a list. The type of this in the <init> method of Object is Object; in other <init> methods, the type of this is uninitializedThis; otherwise, the type of this in an instance method is class(N, L) where N is the name of the class containing the method and L is its defining class loader.
For the initial type state of a static method, this is irrelevant, so the list is empty.
methodInitialThisType(_Class, Method, []) :-
methodAccessFlags(Method, AccessFlags),
member(static, AccessFlags),
methodName(Method, MethodName),
MethodName = '<init>'.
methodInitialThisType(Class, Method, [This]) :-
methodAccessFlags(Method, AccessFlags),
notMember(static, AccessFlags),
instanceMethodInitialThisType(Class, Method, This).
instanceMethodInitialThisType(Class, Method, class('java/lang/Object', L)) :-
methodName(Method, '<init>'),
classDefiningLoader(Class, L),
isBootstrapLoader(L),
classClassName(Class, 'java/lang/Object').
instanceMethodInitialThisType(Class, Method, uninitializedThis) :-
methodName(Method, '<init>'),
classClassName(Class, ClassName),
classDefiningLoader(Class, CurrentLoader),
superclassChain(ClassName, CurrentLoader, Chain),
Chain = [].
instanceMethodInitialThisType(Class, Method, class(ClassName, L)) :-
methodName(Method, MethodName),
MethodName = '<init>',
classDefiningLoader(Class, L),
classClassName(Class, ClassName).
We now compute whether the merged stream for a method is type correct, using the method's initial type state:
-
If we have a stack map frame and an incoming type state, the type state must be assignable to the one in the stack map frame. We may then proceed to type check the rest of the stream with the type state given in the stack map frame.
mergedCodeIsTypeSafe(Environment, [stackMap(Offset, MapFrame) | MoreCode], frame(Locals, OperandStack, Flags)) :- frameIsAssignable(frame(Locals, OperandStack, Flags), MapFrame), mergedCodeIsTypeSafe(Environment, MoreCode, MapFrame). -
A merged code stream is type safe relative to an incoming type state
Tif it begins with an instructionIthat is type safe relative toT, andIsatisfies its exception handlers (see below), and the tail of the stream is type safe given the type state following that execution ofI.NextStackFrameindicates what falls through to the following instruction. For an unconditional branch instruction, it will have the special valueafterGoto.ExceptionStackFrameindicates what is passed to exception handlers.mergedCodeIsTypeSafe(Environment, [instruction(Offset, Parse) | MoreCode], frame(Locals, OperandStack, Flags)) :- instructionIsTypeSafe(Parse, Environment, Offset, frame(Locals, OperandStack, Flags), NextStackFrame, ExceptionStackFrame), instructionSatisfiesHandlers(Environment, Offset, ExceptionStackFrame), mergedCodeIsTypeSafe(Environment, MoreCode, NextStackFrame). -
After an unconditional branch (indicated by an incoming type state of
afterGoto), if we have a stack map frame giving the type state for the following instructions, we can proceed and type check them using the type state provided by the stack map frame.mergedCodeIsTypeSafe(Environment, [stackMap(Offset, MapFrame) | MoreCode], afterGoto) :- mergedCodeIsTypeSafe(Environment, MoreCode, MapFrame). -
It is illegal to have code after an unconditional branch without a stack map frame being provided for it.
mergedCodeIsTypeSafe(_Environment, [instruction(_, _) | _MoreCode], afterGoto) :- write_ln('No stack frame after unconditional branch'), fail. -
If we have an unconditional branch at the end of the code, stop.
mergedCodeIsTypeSafe(_Environment, [endOfCode(Offset)], afterGoto).
Branching to a target is type safe if the target has an associated stack frame, Frame, and the current stack frame, StackFrame, is assignable to Frame.
targetIsTypeSafe(Environment, StackFrame, Target) :-
offsetStackFrame(Environment, Target, Frame),
frameIsAssignable(StackFrame, Frame).
An instruction satisfies its exception handlers if it satisfies every exception handler that is applicable to the instruction.
instructionSatisfiesHandlers(Environment, Offset, ExceptionStackFrame) :-
exceptionHandlers(Environment, Handlers),
sublist(isApplicableHandler(Offset), Handlers, ApplicableHandlers),
checklist(instructionSatisfiesHandler(Environment, ExceptionStackFrame),
ApplicableHandlers).
An exception handler is applicable to an instruction if the offset of the instruction is greater or equal to the start of the handler's range and less than the end of the handler's range.
isApplicableHandler(Offset, handler(Start, End, _Target, _ClassName)) :-
Offset >= Start,
Offset < End.
An instruction satisfies an exception handler if the instructions's outgoing type state is ExcStackFrame, and the handler's target (the initial instruction of the handler code) is type safe assuming an incoming type state T. The type state T is derived from ExcStackFrame by replacing the operand stack with a stack whose sole element is the handler's exception class.
instructionSatisfiesHandler(Environment, ExcStackFrame, Handler) :-
Handler = handler(_, _, Target, _),
currentClassLoader(Environment, CurrentLoader),
handlerExceptionClass(Handler, ExceptionClass, CurrentLoader),
/* The stack consists of just the exception. */
ExcStackFrame = frame(Locals, _, Flags),
TrueExcStackFrame = frame(Locals, [ ExceptionClass ], Flags),
operandStackHasLegalLength(Environment, TrueExcStackFrame),
targetIsTypeSafe(Environment, TrueExcStackFrame, Target).
All load instructions are variations on a common pattern, varying the type of the value that the instruction loads.
Loading a value of type Type from local variable Index is type safe, if the type of that local variable is ActualType, ActualType is assignable to Type, and pushing ActualType onto the incoming operand stack is a valid type transition (§4.10.1.4) that yields a new type state NextStackFrame. After execution of the load instruction, the type state will be NextStackFrame.
loadIsTypeSafe(Environment, Index, Type, StackFrame, NextStackFrame) :-
StackFrame = frame(Locals, _OperandStack, _Flags),
nth0(Index, Locals, ActualType),
isAssignable(ActualType, Type),
validTypeTransition(Environment, [], ActualType, StackFrame,
NextStackFrame).
All store instructions are variations on a common pattern, varying the type of the value that the instruction stores.
In general, a store instruction is type safe if the local variable it references is of a type that is a supertype of Type, and the top of the operand stack is of a subtype of Type, where Type is the type the instruction is designed to store.
More precisely, the store is type safe if one can pop a type ActualType that "matches" Type (that is, is a subtype of Type) off the operand stack (§4.10.1.4), and then legally assign that type the local variable LIndex.
storeIsTypeSafe(_Environment, Index, Type,
frame(Locals, OperandStack, Flags),
frame(NextLocals, NextOperandStack, Flags)) :-
popMatchingType(OperandStack, Type, NextOperandStack, ActualType),
modifyLocalVariable(Index, ActualType, Locals, NextLocals).
Given local variables Locals, modifying Index to have type Type results in the local variable list NewLocals. The modifications are somewhat involved, because some values (and their corresponding types) occupy two local variables. Hence, modifying LN may require modifying LN+1 (because the type will occupy both the N and N+1 slots) or LN-1 (because local N used to be the upper half of the two word value/type starting at local N-1, and so local N-1 must be invalidated), or both. This is described further below. We start at L0 and count up.
modifyLocalVariable(Index, Type, Locals, NewLocals) :-
modifyLocalVariable(0, Index, Type, Locals, NewLocals).
Given LocalsRest, the suffix of the local variable list starting at index I, modifying local variable Index to have type Type results in the local variable list suffix NextLocalsRest.
If I < Index-1, just copy the input to the output and recurse forward. If I = Index-1, the type of local I may change. This can occur if LI has a type of size 2. Once we set LI+1 to the new type (and the corresponding value), the type/value of LI will be invalidated, as its upper half will be trashed. Then we recurse forward.
modifyLocalVariable(I, Index, Type,
[Locals1 | LocalsRest],
[Locals1 | NextLocalsRest] ) :-
I < Index - 1,
I1 is I + 1,
modifyLocalVariable(I1, Index, Type, LocalsRest, NextLocalsRest).
modifyLocalVariable(I, Index, Type,
[Locals1 | LocalsRest],
[NextLocals1 | NextLocalsRest] ) :-
I =:= Index - 1,
modifyPreIndexVariable(Locals1, NextLocals1),
modifyLocalVariable(Index, Index, Type, LocalsRest, NextLocalsRest).
When we find the variable, and it only occupies one word, we change it to Type and we're done. When we find the variable, and it occupies two words, we change its type to Type and the next word to top.
modifyLocalVariable(Index, Index, Type,
[_ | LocalsRest], [Type | LocalsRest]) :-
sizeOf(Type, 1).
modifyLocalVariable(Index, Index, Type,
[_, _ | LocalsRest], [Type, top | LocalsRest]) :-
sizeOf(Type, 2).
We refer to a local whose index immediately precedes a local whose type will be modified as a pre-index variable. The future type of a pre-index variable of type InputType is Result. If the type, Type, of the pre-index local is of size 1, it doesn't change. If the type of the pre-index local, Type, is 2, we need to mark the lower half of its two word value as unusable, by setting its type to top.
modifyPreIndexVariable(Type, Type) :- sizeOf(Type, 1). modifyPreIndexVariable(Type, top) :- sizeOf(Type, 2).
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:
-
If the name of a class is not the name of any superclass, it cannot be a superclass, and so it can safely be ignored.
passesProtectedCheck(Environment, MemberClassName, MemberName, MemberDescriptor, StackFrame) :- thisClass(Environment, class(CurrentClassName, CurrentLoader)), superclassChain(CurrentClassName, CurrentLoader, Chain), notMember(class(MemberClassName, _), Chain). -
If the
MemberClassNameis the same as the name of a superclass, the class being resolved may indeed be a superclass. In this case, if no superclass namedMemberClassNamein a different run-time package has aprotectedmember namedMemberNamewith descriptorMemberDescriptor, theprotectedcheck does not apply.This is because the actual class being resolved will either be one of these superclasses, in which case we know that it is either in the same run-time package, and the access is legal; or the member in question is not
protectedand the check does not apply; or it will be a subclass, in which case the check would succeed anyway; or it will be some other class in the same run-time package, in which case the access is legal and the check need not take place; or the verifier need not flag this as a problem, since it will be caught anyway because resolution will per force fail.passesProtectedCheck(Environment, MemberClassName, MemberName, MemberDescriptor, StackFrame) :- thisClass(Environment, class(CurrentClassName, CurrentLoader)), superclassChain(CurrentClassName, CurrentLoader, Chain), member(class(MemberClassName, _), Chain), classesInOtherPkgWithProtectedMember( class(CurrentClassName, CurrentLoader), MemberName, MemberDescriptor, MemberClassName, Chain, []). -
If there does exist a
protectedsuperclass member in a different run-time package, then loadMemberClassName; if the member in question is notprotected, the check does not apply. (Using a superclass member that is notprotectedis trivially correct.)passesProtectedCheck(Environment, MemberClassName, MemberName, MemberDescriptor, frame(_Locals, [Target | Rest], _Flags)) :- thisClass(Environment, class(CurrentClassName, CurrentLoader)), superclassChain(CurrentClassName, CurrentLoader, Chain), member(class(MemberClassName, _), Chain), classesInOtherPkgWithProtectedMember( class(CurrentClassName, CurrentLoader), MemberName, MemberDescriptor, MemberClassName, Chain, List), List = [], loadedClass(MemberClassName, CurrentLoader, ReferencedClass), isNotProtected(ReferencedClass, MemberName, MemberDescriptor). -
Otherwise, use of a member of an object of type
Targetrequires thatTargetbe assignable to the type of the current class.passesProtectedCheck(Environment, MemberClassName, MemberName, MemberDescriptor, frame(_Locals, [Target | Rest], _Flags)) :- thisClass(Environment, class(CurrentClassName, CurrentLoader)), superclassChain(CurrentClassName, CurrentLoader, Chain), member(class(MemberClassName, _), Chain), classesInOtherPkgWithProtectedMember( class(CurrentClassName, CurrentLoader), MemberName, MemberDescriptor, MemberClassName, Chain, List), List = [], loadedClass(MemberClassName, CurrentLoader, ReferencedClass), isProtected(ReferencedClass, MemberName, MemberDescriptor), isAssignable(Target, class(CurrentClassName, CurrentLoader)).
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) | Tail],
[class(MemberClassName, L) | T]) :-
differentRuntimePackage(Class, class(MemberClassName, L)),
loadedClass(MemberClassName, L, Super),
isProtected(Super, MemberName, MemberDescriptor),
classesInOtherPkgWithProtectedMember(
Class, MemberName, MemberDescriptor, MemberClassName, Tail, T).
classesInOtherPkgWithProtectedMember(Class, MemberName,
MemberDescriptor, MemberClassName,
[class(MemberClassName, L) | Tail],
T) :-
differentRuntimePackage(Class, class(MemberClassName, L)),
loadedClass(MemberClassName, L, Super),
isNotProtected(Super, MemberName, MemberDescriptor),
classesInOtherPkgWithProtectedMember(
Class, MemberName, MemberDescriptor, MemberClassName, Tail, T).
classesInOtherPkgWithProtectedMember(Class, MemberName,
MemberDescriptor, MemberClassName,
[class(MemberClassName, L) | Tail],
T] :-
sameRuntimePackage(Class, class(MemberClassName, L)),
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).
In general, the type rule for an instruction is given relative to an environment Environment that defines the class and method in which the instruction occurs (§4.10.1.1), and the offset Offsetwithin the method at which the instruction occurs. The rule states that if the incoming type state StackFrame fulfills certain requirements, then:
-
It is provable that the type state after the instruction completes normally has a particular form given by
NextStackFrame, and that the type state after the instruction completes abruptly is given byExceptionStackFrame.The type state after an instruction completes abruptly is the same as the incoming type state, except that the operand stack is empty.
exceptionStackFrame(StackFrame, ExceptionStackFrame) :- StackFrame = frame(Locals, _OperandStack, Flags), ExceptionStackFrame = frame(Locals, [], Flags).
Many instructions have type rules that are completely isomorphic to the rules for other instructions. If an instruction b1 is isomorphic to another instruction b2, then the type rule for b1 is the same as the type rule for b2.
instructionIsTypeSafe(Instruction, Environment, Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
instructionHasEquivalentTypeRule(Instruction, IsomorphicInstruction),
instructionIsTypeSafe(IsomorphicInstruction, Environment, Offset,
StackFrame, NextStackFrame,
ExceptionStackFrame).
The English language description of each rule is intended to be readable, intuitive, and concise. As such, the description avoids repeating all the contextual assumptions given above. In particular:
-
The description does not explicitly mention the environment.
-
When the description speaks of the operand stack or local variables in the following, it is referring to the operand stack and local variable components of a type state: either the incoming type state or the outgoing one.
-
The type state after the instruction completes abruptly is almost always identical to the incoming type state. The description only discusses the type state after the instruction completes abruptly when that is not the case.
-
The description speaks of popping and pushing types onto the operand stack, and does not explicitly discuss issues of stack underflow or overflow. The description assumes these operations can be completed successfully, but the Prolog clauses for operand stack manipulation ensure that the necessary checks are made.
-
The description discusses only the manipulation of logical types. In practice, some types take more than one word. The description abstracts from these representation details, but the Prolog clauses that manipulate data do not.
Any ambiguities can be resolved by referring to the formal Prolog clauses.
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(class('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).
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,
[class('java/lang/Object', BL),
int,
arrayOf(class('java/lang/Object', BL))],
NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
An aconst_null instruction is type safe if one can validly push the type null onto the incoming operand stack yielding the outgoing type state.
instructionIsTypeSafe(aconst_null, Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
validTypeTransition(Environment, [], null, StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
An aload instruction with operand Index is type safe and yields an outgoing type state NextStackFrame, if a load instruction with operand Index and type reference is type safe and yields an outgoing type state NextStackFrame.
instructionIsTypeSafe(aload(Index), Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
loadIsTypeSafe(Environment, Index, reference, StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
The instructions aload_<n>, for 0 ≤ n ≤ 3, are type safe iff the equivalent aload instruction is type safe.
instructionHasEquivalentTypeRule(aload_0, aload(0)). instructionHasEquivalentTypeRule(aload_1, aload(1)). instructionHasEquivalentTypeRule(aload_2, aload(2)). instructionHasEquivalentTypeRule(aload_3, aload(3)).
An anewarray instruction with operand CP is type safe iff CP refers to a constant pool entry denoting a class, interface, or array type, and one can legally replace a type matching int on the incoming operand stack with an array with component type CP yielding the outgoing type state.
instructionIsTypeSafe(anewarray(CP), Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
(CP = class(_, _) ; CP = arrayOf(_)),
validTypeTransition(Environment, [int], arrayOf(CP),
StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
An areturn instruction is type safe iff the enclosing method has a declared return type, ReturnType, that is a reference type, and one can validly pop a type matching ReturnType off the incoming operand stack.
instructionIsTypeSafe(areturn, Environment, _Offset, StackFrame,
afterGoto, ExceptionStackFrame) :-
thisMethodReturnType(Environment, ReturnType),
isAssignable(ReturnType, reference),
canPop(StackFrame, [ReturnType], _PoppedStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
An arraylength instruction is type safe iff one can validly replace an array type on the incoming operand stack with the type int yielding the outgoing type state.
instructionIsTypeSafe(arraylength, Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
nth1OperandStackIs(1, StackFrame, ArrayType),
arrayComponentType(ArrayType, _),
validTypeTransition(Environment, [top], int, StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
An astore instruction with operand Index is type safe and yields an outgoing type state NextStackFrame, if a store instruction with operand Index and type reference is type safe and yields an outgoing type state NextStackFrame.
instructionIsTypeSafe(astore(Index), Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
storeIsTypeSafe(Environment, Index, reference, StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
The instructions astore_<n>, for 0 ≤ n ≤ 3, are type safe iff the equivalent astore instruction is type safe.
instructionHasEquivalentTypeRule(astore_0, astore(0)). instructionHasEquivalentTypeRule(astore_1, astore(1)). instructionHasEquivalentTypeRule(astore_2, astore(2)). instructionHasEquivalentTypeRule(astore_3, astore(3)).
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, [class('java/lang/Throwable', BL)], _PoppedStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
A baload instruction is type safe iff one can validly replace types matching int and a small array type on the incoming operand stack with int yielding the outgoing type state.
instructionIsTypeSafe(baload, Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :
nth1OperandStackIs(2, StackFrame, ArrayType),
isSmallArray(ArrayType),
validTypeTransition(Environment, [int, top], int,
StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
An array type is a small array type if it is an array of byte, an array of boolean, or a subtype thereof (null).
isSmallArray(arrayOf(byte)). isSmallArray(arrayOf(boolean)). isSmallArray(null).
A bastore instruction is type safe iff one can validly pop types matching int, int and a small array type off the incoming operand stack yielding the outgoing type state.
instructionIsTypeSafe(bastore, _Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
nth1OperandStackIs(3, StackFrame, ArrayType),
isSmallArray(ArrayType),
canPop(StackFrame, [int, int, top], NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
A bipush instruction is type safe iff the equivalent sipush instruction is type safe.
instructionHasEquivalentTypeRule(bipush(Value), sipush(Value)).
A caload instruction is type safe iff one can validly replace types matching int and array of char on the incoming operand stack with int yielding the outgoing type state.
instructionIsTypeSafe(caload, Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
validTypeTransition(Environment, [int, arrayOf(char)], int,
StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
A castore instruction is type safe iff one can validly pop types matching int, int and array of char off the incoming operand stack yielding the outgoing type state.
instructionIsTypeSafe(castore, _Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
canPop(StackFrame, [int, int, arrayOf(char)], NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
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(_)),
isBootstrapLoader(BL),
validTypeTransition(Environment, [class('java/lang/Object', BL)], CP,
StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
A d2f instruction is type safe if one can validly pop double off the incoming operand stack and replace it with float, yielding the outgoing type state.
instructionIsTypeSafe(d2f, Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
validTypeTransition(Environment, [double], float,
StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
A d2i instruction is type safe if one can validly pop double off the incoming operand stack and replace it with int, yielding the outgoing type state.
instructionIsTypeSafe(d2i, Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
validTypeTransition(Environment, [double], int,
StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
A d2l instruction is type safe if one can validly pop double off the incoming operand stack and replace it with long, yielding the outgoing type state.
instructionIsTypeSafe(d2l, Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
validTypeTransition(Environment, [double], long,
StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
A dadd instruction is type safe iff one can validly replace types matching double and double on the incoming operand stack with double yielding the outgoing type state.
instructionIsTypeSafe(dadd, Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
validTypeTransition(Environment, [double, double], double,
StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
A daload instruction is type safe iff one can validly replace types matching int and array of double on the incoming operand stack with double yielding the outgoing type state.
instructionIsTypeSafe(daload, Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
validTypeTransition(Environment, [int, arrayOf(double)], double,
StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
A dastore instruction is type safe iff one can validly pop types matching double, int and array of double off the incoming operand stack yielding the outgoing type state.
instructionIsTypeSafe(dastore, _Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
canPop(StackFrame, [double, int, arrayOf(double)], NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
A dcmpg instruction is type safe iff one can validly replace types matching double and double on the incoming operand stack with int yielding the outgoing type state.
instructionIsTypeSafe(dcmpg, Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
validTypeTransition(Environment, [double, double], int,
StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
A dcmpl instruction is type safe iff the equivalent dcmpg instruction is type safe.
instructionHasEquivalentTypeRule(dcmpl, dcmpg).
A dconst_0 instruction is type safe if one can validly push the type double onto the incoming operand stack yielding the outgoing type state.
instructionIsTypeSafe(dconst_0, Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
validTypeTransition(Environment, [], double, StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
A dconst_1 instruction is type safe iff the equivalent dconst_0 instruction is type safe.
instructionHasEquivalentTypeRule(dconst_1, dconst_0).
A ddiv instruction is type safe iff the equivalent dadd instruction is type safe.
instructionHasEquivalentTypeRule(ddiv, dadd).
A dload instruction with operand Index is type safe and yields an outgoing type state NextStackFrame, if a load instruction with operand Index and type double is type safe and yields an outgoing type state NextStackFrame.
instructionIsTypeSafe(dload(Index), Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
loadIsTypeSafe(Environment, Index, double, StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
The instructions dload_<n>, for 0 ≤ n ≤ 3, are typesafe iff the equivalent dload instruction is type safe.
instructionHasEquivalentTypeRule(dload_0, dload(0)). instructionHasEquivalentTypeRule(dload_1, dload(1)). instructionHasEquivalentTypeRule(dload_2, dload(2)). instructionHasEquivalentTypeRule(dload_3, dload(3)).
A dmul instruction is type safe iff the equivalent dadd instruction is type safe.
instructionHasEquivalentTypeRule(dmul, dadd).
A dneg instruction is type safe iff there is a type matching double on the incoming operand stack. The dneg instruction does not alter the type state.
instructionIsTypeSafe(dneg, Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
validTypeTransition(Environment, [double], double,
StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
A drem instruction is type safe iff the equivalent dadd instruction is type safe.
instructionHasEquivalentTypeRule(drem, dadd).
A dreturn instruction is type safe if the enclosing method has a declared return type of double, and one can validly pop a type matching double off the incoming operand stack.
instructionIsTypeSafe(dreturn, Environment, _Offset, StackFrame,
afterGoto, ExceptionStackFrame) :-
thisMethodReturnType(Environment, double),
canPop(StackFrame, [double], _PoppedStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
A dstore instruction with operand Index is type safe and yields an outgoing type state NextStackFrame, if a store instruction with operand Index and type double is type safe and yields an outgoing type state NextStackFrame.
instructionIsTypeSafe(dstore(Index), Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
storeIsTypeSafe(Environment, Index, double, StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
The instructions dstore_<n>, for 0 ≤ n ≤ 3, are type safe iff the equivalent dstore instruction is type safe.
instructionHasEquivalentTypeRule(dstore_0, dstore(0)). instructionHasEquivalentTypeRule(dstore_1, dstore(1)). instructionHasEquivalentTypeRule(dstore_2, dstore(2)). instructionHasEquivalentTypeRule(dstore_3, dstore(3)).
A dsub instruction is type safe iff the equivalent dadd instruction is type safe.
instructionHasEquivalentTypeRule(dsub, dadd).
A dup instruction is type safe iff one can validly replace a category 1 type, Type, with the types Type, Type, yielding the outgoing type state.
instructionIsTypeSafe(dup, Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
StackFrame = frame(Locals, InputOperandStack, Flags),
popCategory1(InputOperandStack, Type, _),
canSafelyPush(Environment, InputOperandStack, Type, OutputOperandStack),
NextStackFrame = frame(Locals, OutputOperandStack, Flags),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
A dup_x1 instruction is type safe iff one can validly replace two category 1 types, Type1, and Type2, on the incoming operand stack with the types Type1, Type2, Type1, yielding the outgoing type state.
instructionIsTypeSafe(dup_x1, Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
StackFrame = frame(Locals, InputOperandStack, Flags),
popCategory1(InputOperandStack, Type1, Stack1),
popCategory1(Stack1, Type2, Rest),
canSafelyPushList(Environment, Rest, [Type1, Type2, Type1],
OutputOperandStack),
NextStackFrame = frame(Locals, OutputOperandStack, Flags),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
A dup_x2 instruction is type safe iff it is a type safe form of the dup_x2 instruction.
instructionIsTypeSafe(dup_x2, Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
StackFrame = frame(Locals, InputOperandStack, Flags),
dup_x2FormIsTypeSafe(Environment, InputOperandStack, OutputOperandStack),
NextStackFrame = frame(Locals, OutputOperandStack, Flags),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
A dup_x2 instruction is a type safe form of the dup_x2 instruction iff it is a type safe form 1 dup_x2 instruction or a type safe form 2 dup_x2 instruction.
dup_x2FormIsTypeSafe(Environment, InputOperandStack, OutputOperandStack) :-
dup_x2Form1IsTypeSafe(Environment, InputOperandStack, OutputOperandStack).
dup_x2FormIsTypeSafe(Environment, InputOperandStack, OutputOperandStack) :-
dup_x2Form2IsTypeSafe(Environment, InputOperandStack, OutputOperandStack).
A dup_x2 instruction is a type safe form 1 dup_x2 instruction iff one can validly replace three category 1 types, Type1, Type2, Type3 on the incoming operand stack with the types Type1, Type2, Type3, Type1, yielding the outgoing type state.
dup_x2Form1IsTypeSafe(Environment, InputOperandStack, OutputOperandStack) :-
popCategory1(InputOperandStack, Type1, Stack1),
popCategory1(Stack1, Type2, Stack2),
popCategory1(Stack2, Type3, Rest),
canSafelyPushList(Environment, Rest, [Type1, Type3, Type2, Type1],
OutputOperandStack).
A dup_x2 instruction is a type safe form 2 dup_x2 instruction iff one can validly replace a category 1 type, Type1, and a category 2 type, Type2, on the incoming operand stack with the types Type1, Type2, Type1, yielding the outgoing type state.
dup_x2Form2IsTypeSafe(Environment, InputOperandStack, OutputOperandStack) :-
popCategory1(InputOperandStack, Type1, Stack1),
popCategory2(Stack1, Type2, Rest),
canSafelyPushList(Environment, Rest, [Type1, Type2, Type1],
OutputOperandStack).
A dup2 instruction is type safe iff it is a type safe form of the dup2 instruction.
instructionIsTypeSafe(dup2, Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
StackFrame = frame(Locals, InputOperandStack, Flags),
dup2FormIsTypeSafe(Environment,InputOperandStack, OutputOperandStack),
NextStackFrame = frame(Locals, OutputOperandStack, Flags),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
A dup2 instruction is a type safe form of the dup2 instruction iff it is a type safe form 1 dup2 instruction or a type safe form 2 dup2 instruction.
dup2FormIsTypeSafe(Environment, InputOperandStack, OutputOperandStack) :-
dup2Form1IsTypeSafe(Environment,InputOperandStack, OutputOperandStack).
dup2FormIsTypeSafe(Environment, InputOperandStack, OutputOperandStack) :-
dup2Form2IsTypeSafe(Environment,InputOperandStack, OutputOperandStack).
A dup2 instruction is a type safe form 1 dup2 instruction iff one can validly replace two category 1 types, Type1 and Type2 on the incoming operand stack with the types Type1, Type2, Type1, Type2, yielding the outgoing type state.
dup2Form1IsTypeSafe(Environment, InputOperandStack, OutputOperandStack):-
popCategory1(InputOperandStack, Type1, TempStack),
popCategory1(TempStack, Type2, _),
canSafelyPushList(Environment, InputOperandStack, [Type1, Type2],
OutputOperandStack).
A dup2 instruction is a type safe form 2 dup2 instruction iff one can validly replace a category 2 type, Type on the incoming operand stack with the types Type, Type, yielding the outgoing type state.
dup2Form2IsTypeSafe(Environment, InputOperandStack, OutputOperandStack):-
popCategory2(InputOperandStack, Type, _),
canSafelyPush(Environment, InputOperandStack, Type, OutputOperandStack).
A dup2_x1 instruction is type safe iff it is a type safe form of the dup2_x1 instruction.
instructionIsTypeSafe(dup2_x1, Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
StackFrame = frame(Locals, InputOperandStack, Flags),
dup2_x1FormIsTypeSafe(Environment, InputOperandStack, OutputOperandStack),
NextStackFrame = frame(Locals, OutputOperandStack, Flags),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
A dup2_x1 instruction is a type safe form of the dup2_x1 instruction iff it is a type safe form 1 dup2_x1 instruction or a type safe form 2 dup_x2 instruction.
dup2_x1FormIsTypeSafe(Environment, InputOperandStack, OutputOperandStack) :-
dup2_x1Form1IsTypeSafe(Environment, InputOperandStack, OutputOperandStack).
dup2_x1FormIsTypeSafe(Environment, InputOperandStack, OutputOperandStack) :-
dup2_x1Form2IsTypeSafe(Environment, InputOperandStack, OutputOperandStack).
A dup2_x1 instruction is a type safe form 1 dup2_x1 instruction iff one can validly replace three category 1 types, Type1, Type2, Type3, on the incoming operand stack with the types Type1, Type2, Type3, Type1, Type2, yielding the outgoing type state.
dup2_x1Form1IsTypeSafe(Environment, InputOperandStack, OutputOperandStack) :-
popCategory1(InputOperandStack, Type1, Stack1),
popCategory1(Stack1, Type2, Stack2),
popCategory1(Stack2, Type3, Rest),
canSafelyPushList(Environment, Rest, [Type2, Type1, Type3, Type2, Type1],
OutputOperandStack).
A dup2_x1 instruction is a type safe form 2 dup2_x1 instruction iff one can validly replace a category 2 type, Type1, and a category 1 type, Type2, on the incoming operand stack with the types Type1, Type2, Type1, yielding the outgoing type state.
dup2_x1Form2IsTypeSafe(Environment, InputOperandStack, OutputOperandStack) :-
popCategory2(InputOperandStack, Type1, Stack1),
popCategory1(Stack1, Type2, Rest),
canSafelyPushList(Environment, Rest, [Type1, Type2, Type1],
OutputOperandStack).
A dup2_x2 instruction is type safe iff it is a type safe form of the dup2_x2 instruction.
instructionIsTypeSafe(dup2_x2, Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
StackFrame = frame(Locals, InputOperandStack, Flags),
dup2_x2FormIsTypeSafe(Environment, InputOperandStack, OutputOperandStack),
NextStackFrame = frame(Locals, OutputOperandStack, Flags),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
A dup2_x2 instruction is a type safe form of the dup2_x2 instruction iff one of the following holds:
dup2_x2FormIsTypeSafe(Environment, InputOperandStack, OutputOperandStack) :-
dup2_x2Form1IsTypeSafe(Environment, InputOperandStack, OutputOperandStack).
dup2_x2FormIsTypeSafe(Environment, InputOperandStack, OutputOperandStack) :-
dup2_x2Form2IsTypeSafe(Environment, InputOperandStack, OutputOperandStack).
dup2_x2FormIsTypeSafe(Environment, InputOperandStack, OutputOperandStack) :-
dup2_x2Form3IsTypeSafe(Environment, InputOperandStack, OutputOperandStack).
dup2_x2FormIsTypeSafe(Environment, InputOperandStack, OutputOperandStack) :-
dup2_x2Form4IsTypeSafe(Environment, InputOperandStack, OutputOperandStack).
A dup2_x2 instruction is a type safe form 1 dup2_x2 instruction iff one can validly replace four category 1 types, Type1, Type2, Type3, Type4, on the incoming operand stack with the types Type1, Type2, Type3, Type4, Type1, Type2, yielding the outgoing type state.
dup2_x2Form1IsTypeSafe(Environment, InputOperandStack, OutputOperandStack) :-
popCategory1(InputOperandStack, Type1, Stack1),
popCategory1(Stack1, Type2, Stack2),
popCategory1(Stack2, Type3, Stack3),
popCategory1(Stack3, Type4, Rest),
canSafelyPushList(Environment, Rest,
[Type2, Type1, Type4, Type3, Type2, Type1],
OutputOperandStack).
A dup2_x2 instruction is a type safe form 2 dup2_x2 instruction iff one can validly replace a category 2 type, Type1, and two category 1 types, Type2, Type3, on the incoming operand stack with the types Type1, Type2, Type3, Type1, yielding the outgoing type state.
dup2_x2Form2IsTypeSafe(Environment, InputOperandStack, OutputOperandStack) :-
popCategory2(InputOperandStack, Type1, Stack1),
popCategory1(Stack1, Type2, Stack2),
popCategory1(Stack2, Type3, Rest),
canSafelyPushList(Environment, Rest,
[Type1, Type3, Type2, Type1],
OutputOperandStack).
A dup2_x2 instruction is a type safe form 3 dup2_x2 instruction iff one can validly replace two category 1 types, Type1, Type2, and a category 2 type, Type3, on the incoming operand stack with the types Type1, Type2, Type3, Type1, Type2, yielding the outgoing type state.
dup2_x2Form3IsTypeSafe(Environment, InputOperandStack, OutputOperandStack) :-
popCategory1(InputOperandStack, Type1, Stack1),
popCategory1(Stack1, Type2, Stack2),
popCategory2(Stack2, Type3, Rest),
canSafelyPushList(Environment, Rest,
[Type2, Type1, Type3, Type2, Type1],
OutputOperandStack).
A dup2_x2 instruction is a type safe form 4 dup2_x2 instruction iff one can validly replace two category 2 types, Type1, Type2, on the incoming operand stack with the types Type1, Type2, Type1, yielding the outgoing type state.
dup2_x2Form4IsTypeSafe(Environment, InputOperandStack, OutputOperandStack) :-
popCategory2(InputOperandStack, Type1, Stack1),
popCategory2(Stack1, Type2, Rest),
canSafelyPushList(Environment, Rest, [Type1, Type2, Type1],
OutputOperandStack).
An f2d instruction is type safe if one can validly pop float off the incoming operand stack and replace it with double, yielding the outgoing type state.
instructionIsTypeSafe(f2d, Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
validTypeTransition(Environment, [float], double,
StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
An f2i instruction is type safe if one can validly pop float off the incoming operand stack and replace it with int, yielding the outgoing type state.
instructionIsTypeSafe(f2i, Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
validTypeTransition(Environment, [float], int,
StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
An f2l instruction is type safe if one can validly pop float off the incoming operand stack and replace it with long, yielding the outgoing type state.
instructionIsTypeSafe(f2l, Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
validTypeTransition(Environment, [float], long,
StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
An fadd instruction is type safe iff one can validly replace types matching float and float on the incoming operand stack with float yielding the outgoing type state.
instructionIsTypeSafe(fadd, Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
validTypeTransition(Environment, [float, float], float,
StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
An faload instruction is type safe iff one can validly replace types matching int and array of float on the incoming operand stack with float yielding the outgoing type state.
instructionIsTypeSafe(faload, Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
validTypeTransition(Environment, [int, arrayOf(float)], float,
StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
An fastore instruction is type safe iff one can validly pop types matching float, int and array of float off the incoming operand stack yielding the outgoing type state.
instructionIsTypeSafe(fastore, _Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
canPop(StackFrame, [float, int, arrayOf(float)], NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
An fcmpg instruction is type safe iff one can validly replace types matching float and float on the incoming operand stack with int yielding the outgoing type state.
instructionIsTypeSafe(fcmpg, Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
validTypeTransition(Environment, [float, float], int,
StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
An fcmpl instruction is type safe iff the equivalent fcmpg instruction is type safe.
instructionHasEquivalentTypeRule(fcmpl, fcmpg).
An fconst_0 instruction is type safe if one can validly push the type float onto the incoming operand stack yielding the outgoing type state.
instructionIsTypeSafe(fconst_0, Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
validTypeTransition(Environment, [], float, StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
The rules for the other variants of fconst are equivalent.
instructionHasEquivalentTypeRule(fconst_1, fconst_0). instructionHasEquivalentTypeRule(fconst_2, fconst_0).
An fdiv instruction is type safe iff the equivalent fadd instruction is type safe.
instructionHasEquivalentTypeRule(fdiv, fadd).
An fload instruction with operand Index is type safe and yields an outgoing type state NextStackFrame, if a load instruction with operand Index and type float is type safe and yields an outgoing type state NextStackFrame.
instructionIsTypeSafe(fload(Index), Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
loadIsTypeSafe(Environment, Index, float, StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
The instructions fload_<n>, for 0 ≤ n ≤ 3, are typesafe iff the equivalent fload instruction is type safe.
instructionHasEquivalentTypeRule(fload_0, fload(0)). instructionHasEquivalentTypeRule(fload_1, fload(1)). instructionHasEquivalentTypeRule(fload_2, fload(2)). instructionHasEquivalentTypeRule(fload_3, fload(3)).
An fmul instruction is type safe iff the equivalent fadd instruction is type safe.
instructionHasEquivalentTypeRule(fmul, fadd).
An fneg instruction is type safe iff there is a type matching float on the incoming operand stack. The fneg instruction does not alter the type state.
instructionIsTypeSafe(fneg, Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
validTypeTransition(Environment, [float], float,
StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
An frem instruction is type safe iff the equivalent fadd instruction is type safe.
instructionHasEquivalentTypeRule(frem, fadd).
An freturn instruction is type safe if the enclosing method has a declared return type of float, and one can validly pop a type matching float off the incoming operand stack.
instructionIsTypeSafe(freturn, Environment, _Offset, StackFrame,
afterGoto, ExceptionStackFrame) :-
thisMethodReturnType(Environment, float),
canPop(StackFrame, [float], _PoppedStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
An fstore instruction with operand Index is type safe and yields an outgoing type state NextStackFrame, if a store instruction with operand Index and type float is type safe and yields an outgoing type state NextStackFrame.
instructionIsTypeSafe(fstore(Index), Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
storeIsTypeSafe(Environment, Index, float, StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
The instructions fstore_<n>, for 0 ≤ n ≤ 3, are typesafe iff the equivalent fstore instruction is type safe.
instructionHasEquivalentTypeRule(fstore_0, fstore(0)). instructionHasEquivalentTypeRule(fstore_1, fstore(1)). instructionHasEquivalentTypeRule(fstore_2, fstore(2)). instructionHasEquivalentTypeRule(fstore_3, fstore(3)).
An fsub instruction is type safe iff the equivalent fadd instruction is type safe.
instructionHasEquivalentTypeRule(fsub, fadd).
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 FieldClassName, and one can validly replace a type matching FieldClassName with type FieldType on the incoming operand stack yielding the outgoing type state. FieldClassName 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(FieldClassName, FieldName, FieldDescriptor),
parseFieldDescriptor(FieldDescriptor, FieldType),
passesProtectedCheck(Environment, FieldClassName, FieldName,
FieldDescriptor, StackFrame),
currentClassLoader(Environment, CurrentLoader),
validTypeTransition(Environment,
[class(FieldClassName, CurrentLoader)], FieldType,
StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
A getstatic instruction with operand CP is type safe iff CP refers to a constant pool entry denoting a field whose declared type is FieldType, and one can validly push FieldType on the incoming operand stack yielding the outgoing type state.
instructionIsTypeSafe(getstatic(CP), Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
CP = field(_FieldClassName, _FieldName, FieldDescriptor),
parseFieldDescriptor(FieldDescriptor, FieldType),
validTypeTransition(Environment, [], FieldType,
StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
A goto instruction is type safe iff its target operand is a valid branch target.
instructionIsTypeSafe(goto(Target), Environment, _Offset, StackFrame,
afterGoto, ExceptionStackFrame) :-
targetIsTypeSafe(Environment, StackFrame, Target),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
A goto_w instruction is type safe iff the equivalent goto instruction is type safe.
instructionHasEquivalentTypeRule(goto_w(Target), goto(Target)).
An i2b instruction is type safe iff the equivalent ineg instruction is type safe.
instructionHasEquivalentTypeRule(i2b, ineg).
An i2c instruction is type safe iff the equivalent ineg instruction is type safe.
instructionHasEquivalentTypeRule(i2c, ineg).
An i2d instruction is type safe if one can validly pop int off the incoming operand stack and replace it with double, yielding the outgoing type state.
instructionIsTypeSafe(i2d, Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
validTypeTransition(Environment, [int], double,
StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
An i2f instruction is type safe if one can validly pop int off the incoming operand stack and replace it with float, yielding the outgoing type state.
instructionIsTypeSafe(i2f, Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
validTypeTransition(Environment, [int], float,
StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
An i2l instruction is type safe if one can validly pop int off the incoming operand stack and replace it with long, yielding the outgoing type state.
instructionIsTypeSafe(i2l, Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
validTypeTransition(Environment, [int], long,
StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
An i2s instruction is type safe iff the equivalent ineg instruction is type safe.
instructionHasEquivalentTypeRule(i2s, ineg).
An iadd instruction is type safe iff one can validly replace types matching int and int on the incoming operand stack with int yielding the outgoing type state.
instructionIsTypeSafe(iadd, Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
validTypeTransition(Environment, [int, int], int,
StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
An iaload instruction is type safe iff one can validly replace types matching int and array of int on the incoming operand stack with int yielding the outgoing type state.
instructionIsTypeSafe(iaload, Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
validTypeTransition(Environment, [int, arrayOf(int)], int,
StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
An iand instruction is type safe iff the equivalent iadd instruction is type safe.
instructionHasEquivalentTypeRule(iand, iadd).
An iastore instruction is type safe iff one can validly pop types matching int, int and array of int off the incoming operand stack yielding the outgoing type state.
instructionIsTypeSafe(iastore, _Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
canPop(StackFrame, [int, int, arrayOf(int)], NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
An iconst_m1 instruction is type safe if one can validly push the type int onto the incoming operand stack yielding the outgoing type state.
instructionIsTypeSafe(iconst_m1, Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
validTypeTransition(Environment, [], int, StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
The rules for the other variants of iconst are equivalent.
instructionHasEquivalentTypeRule(iconst_0, iconst_m1). instructionHasEquivalentTypeRule(iconst_1, iconst_m1). instructionHasEquivalentTypeRule(iconst_2, iconst_m1). instructionHasEquivalentTypeRule(iconst_3, iconst_m1). instructionHasEquivalentTypeRule(iconst_4, iconst_m1). instructionHasEquivalentTypeRule(iconst_5, iconst_m1).
An idiv instruction is type safe iff the equivalent iadd instruction is type safe.
instructionHasEquivalentTypeRule(idiv, iadd).
An if_acmpeq instruction is type safe iff one can validly pop types matching reference and reference on the incoming operand stack yielding the outgoing type state NextStackFrame, and the operand of the instruction, Target, is a valid branch target assuming an incoming type state of NextStackFrame.
instructionIsTypeSafe(if_acmpeq(Target), Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
canPop(StackFrame, [reference, reference], NextStackFrame),
targetIsTypeSafe(Environment, NextStackFrame, Target),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
The rule for if_acmpne is identical.
instructionHasEquivalentTypeRule(if_acmpne(Target), if_acmpeq(Target)).
An if_icmpeq instruction is type safe iff one can validly pop types matching int and int on the incoming operand stack yielding the outgoing type state NextStackFrame, and the operand of the instruction, Target, is a valid branch target assuming an incoming type state of NextStackFrame.
instructionIsTypeSafe(if_icmpeq(Target), Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
canPop(StackFrame, [int, int], NextStackFrame),
targetIsTypeSafe(Environment, NextStackFrame, Target),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
The rules for all other variants of the if_icmp<cond> instruction are identical.
instructionHasEquivalentTypeRule(if_icmpge(Target), if_icmpeq(Target)). instructionHasEquivalentTypeRule(if_icmpgt(Target), if_icmpeq(Target)). instructionHasEquivalentTypeRule(if_icmple(Target), if_icmpeq(Target)). instructionHasEquivalentTypeRule(if_icmplt(Target), if_icmpeq(Target)). instructionHasEquivalentTypeRule(if_icmpne(Target), if_icmpeq(Target)).
An ifeq instruction is type safe iff one can validly pop a type matching int off the incoming operand stack yielding the outgoing type state NextStackFrame, and the operand of the instruction, Target, is a valid branch target assuming an incoming type state of NextStackFrame.
instructionIsTypeSafe(ifeq(Target), Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
canPop(StackFrame, [int], NextStackFrame),
targetIsTypeSafe(Environment, NextStackFrame, Target),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
The rules for all other variations of the if<cond> instruction are identical.
instructionHasEquivalentTypeRule(ifge(Target), ifeq(Target)). instructionHasEquivalentTypeRule(ifgt(Target), ifeq(Target)). instructionHasEquivalentTypeRule(ifle(Target), ifeq(Target)). instructionHasEquivalentTypeRule(iflt(Target), ifeq(Target)). instructionHasEquivalentTypeRule(ifne(Target), ifeq(Target)).
An ifnonnull instruction is type safe iff one can validly pop a type matching reference off the incoming operand stack yielding the outgoing type state NextStackFrame, and the operand of the instruction, Target, is a valid branch target assuming an incoming type state of NextStackFrame.
instructionIsTypeSafe(ifnonnull(Target), Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
canPop(StackFrame, [reference], NextStackFrame),
targetIsTypeSafe(Environment, NextStackFrame, Target),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
An ifnull instruction is type safe iff the equivalent ifnonnull instruction is type safe.
instructionHasEquivalentTypeRule(ifnull(Target), ifnonnull(Target)).
An iinc instruction with first operand Index is type safe iff LIndex has type int. The iinc instruction does not change the type state.
instructionIsTypeSafe(iinc(Index, _Value), _Environment, _Offset,
StackFrame, StackFrame, ExceptionStackFrame) :-
StackFrame = frame(Locals, _OperandStack, _Flags),
nth0(Index, Locals, int),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
An iload instruction with operand Index is type safe and yields an outgoing type state NextStackFrame, if a load instruction with operand Index and type int is type safe and yields an outgoing type state NextStackFrame.
instructionIsTypeSafe(iload(Index), Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
loadIsTypeSafe(Environment, Index, int, StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
The instructions iload_<n>, for 0 ≤ n ≤ 3, are typesafe iff the equivalent iload instruction is type safe.
instructionHasEquivalentTypeRule(iload_0, iload(0)). instructionHasEquivalentTypeRule(iload_1, iload(1)). instructionHasEquivalentTypeRule(iload_2, iload(2)). instructionHasEquivalentTypeRule(iload_3, iload(3)).
An imul instruction is type safe iff the equivalent iadd instruction is type safe.
instructionHasEquivalentTypeRule(imul, iadd).
An ineg instruction is type safe iff there is a type matching int on the incoming operand stack. The ineg instruction does not alter the type state.
instructionIsTypeSafe(ineg, Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
validTypeTransition(Environment, [int], int, StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
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, [class('java/lang/Object', BL)], int,
StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
An invokedynamic instruction is type safe iff all of the following are true:
-
Its first operand,
CP, refers to a constant pool entry denoting an dynamic call site with nameCallSiteNamewith descriptorDescriptor. -
One can validly replace types matching the argument types given in
Descriptoron the incoming operand stack with the return type given inDescriptor, yielding the outgoing type state.
instructionIsTypeSafe(invokedynamic(CP,0,0), Environment, _Offset,
StackFrame, NextStackFrame, ExceptionStackFrame) :-
CP = dmethod(CallSiteName, Descriptor),
CallSiteName = '<init>',
CallSiteName = '<clinit>',
parseMethodDescriptor(Descriptor, OperandArgList, ReturnType),
reverse(OperandArgList, StackArgList),
validTypeTransition(Environment, StackArgList, ReturnType,
StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
An invokeinterface instruction is type safe iff all of the following are true:
-
Its first operand,
CP, refers to a constant pool entry denoting an interface method namedMethodNamewith descriptorDescriptorthat is a member of an interfaceMethodIntfName. -
Its second operand,
Count, is a valid count operand (see below). -
One can validly replace types matching the type
MethodIntfNameand the argument types given inDescriptoron the incoming operand stack with the return type given inDescriptor, yielding the outgoing type state.
instructionIsTypeSafe(invokeinterface(CP, Count, 0), Environment, _Offset,
StackFrame, NextStackFrame, ExceptionStackFrame) :-
CP = imethod(MethodIntfName, MethodName, Descriptor),
MethodName = '<init>',
MethodName = '<clinit>',
parseMethodDescriptor(Descriptor, OperandArgList, ReturnType),
currentClassLoader(Environment, CurrentLoader),
reverse([class(MethodIntfName, CurrentLoader) | 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.
An invokespecial instruction is type safe iff all of the following are true:
-
Its first operand,
CP, refers to a constant pool entry denoting a method namedMethodNamewith descriptorDescriptorthat is a member of a classMethodClassName. -
-
One can validly replace types matching the current class and the argument types given in
Descriptoron the incoming operand stack with the return type given inDescriptor, yielding the outgoing type state. -
One can validly replace types matching the class
MethodClassNameand the argument types given inDescriptoron the incoming operand stack with the return type given inDescriptor.
instructionIsTypeSafe(invokespecial(CP), Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
CP = method(MethodClassName, MethodName, Descriptor),
MethodName = '<init>',
MethodName = '<clinit>',
parseMethodDescriptor(Descriptor, OperandArgList, ReturnType),
thisClass(Environment, class(CurrentClassName, CurrentLoader)),
isAssignable(class(CurrentClassName, CurrentLoader),
class(MethodClassName, CurrentLoader)),
reverse([class(CurrentClassName, CurrentLoader) | OperandArgList],
StackArgList),
validTypeTransition(Environment, StackArgList, ReturnType,
StackFrame, NextStackFrame),
reverse([class(MethodClassName, CurrentLoader) | OperandArgList],
StackArgList2),
validTypeTransition(Environment, StackArgList2, ReturnType,
StackFrame, _ResultStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
The isAssignable clause enforces the structural constraint that invokespecial, for other than an instance initialization method, must name a method in the current class/interface or a superclass/superinterface.
The first validTypeTransition clause enforces the structural constraint that invokespecial, for other than an instance initialization method, targets a receiver object of the current class or deeper. To see why, consider that StackArgList simulates the list of types on the operand stack expected by the method, starting with the current class (the class performing invokespecial). The actual types on the operand stack are in StackFrame. The effect of validTypeTransition is to pop the first type from the operand stack in StackFrame and check it is a subtype of the first term of StackArgList, namely the current class. Thus, the actual receiver type is compatible with the current class.
A sharp-eyed reader might notice that enforcing this structural constraint supercedes the structural constraint pertaining to invokespecial of a protected method. Thus, the Prolog code above makes no reference to passesProtectedCheck (§4.10.1.8), whereas the Prolog code for invokespecial of an instance initialization method uses passesProtectedCheck to ensure the actual receiver type is compatible with the current class when certain protected instance initialization methods are named.
The second validTypeTransition clause enforces the structural constraint that any method invocation instruction must target a receiver object whose type is compatible with the type named by the instruction. To see why, consider that StackArgList2 simulates the list of types on the operand stack expected by the method, starting with the type named by the instruction. Again, the actual types on the operand stack are in StackFrame, and the effect of validTypeTransition is to check the actual receiver type in StackFrame is compatible with the type named by the instruction in StackArgList2.
-
-
One can validly pop types matching the argument types given in
Descriptorand an uninitialized type,UninitializedArg, off the incoming operand stack, yieldingOperandStack. -
The outgoing type state is derived from the incoming type state by first replacing the incoming operand stack with
OperandStackand then replacing all instances ofUninitializedArgwith the type of instance being initialized. -
If the instruction calls an instance initialization method on a class instance created by an earlier new instruction, and the method is
protected, the usage conforms to the special rules governing access toprotectedmembers (§4.10.1.8).
instructionIsTypeSafe(invokespecial(CP), Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
CP = method(MethodClassName, '<init>', Descriptor),
parseMethodDescriptor(Descriptor, OperandArgList, void),
reverse(OperandArgList, StackArgList),
canPop(StackFrame, StackArgList, TempFrame),
TempFrame = frame(Locals, [uninitializedThis | OperandStack], Flags),
currentClassLoader(Environment, CurrentLoader),
rewrittenUninitializedType(uninitializedThis, Environment,
class(MethodClassName, CurrentLoader), This),
rewrittenInitializationFlags(uninitializedThis, Flags, NextFlags),
substitute(uninitializedThis, This, OperandStack, NextOperandStack),
substitute(uninitializedThis, This, Locals, NextLocals),
NextStackFrame = frame(NextLocals, NextOperandStack, NextFlags),
ExceptionStackFrame = frame(Locals, [], Flags).
instructionIsTypeSafe(invokespecial(CP), Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
CP = method(MethodClassName, '<init>', Descriptor),
parseMethodDescriptor(Descriptor, OperandArgList, void),
reverse(OperandArgList, StackArgList),
canPop(StackFrame, StackArgList, TempFrame),
TempFrame = frame(Locals, [uninitialized(Address) | OperandStack], Flags),
currentClassLoader(Environment, CurrentLoader),
rewrittenUninitializedType(uninitialized(Address), Environment,
class(MethodClassName, CurrentLoader), This),
rewrittenInitializationFlags(uninitialized(Address), Flags, NextFlags),
substitute(uninitialized(Address), This, OperandStack, NextOperandStack),
substitute(uninitialized(Address), This, Locals, NextLocals),
NextStackFrame = frame(NextLocals, NextOperandStack, NextFlags),
ExceptionStackFrame = frame(Locals, [], Flags),
passesProtectedCheck(Environment, MethodClassName, '<init>',
Descriptor, NextStackFrame).
To compute what type the uninitialized argument's type needs to be rewritten to, there are two cases:
-
If we are initializing an object within its constructor, its type is initially
uninitializedThis. This type will be rewritten to the type of the class of the<init>method. -
The second case arises from initialization of an object created by new. The uninitialized arg type is rewritten to
MethodClass, the type of the method holder of<init>. We check whether there really is a new instruction atAddress.
rewrittenUninitializedType(uninitializedThis, Environment,
MethodClass, MethodClass) :-
MethodClass = class(MethodClassName, CurrentLoader),
thisClass(Environment, MethodClass).
rewrittenUninitializedType(uninitializedThis, Environment,
MethodClass, MethodClass) :-
MethodClass = class(MethodClassName, CurrentLoader),
thisClass(Environment, class(thisClassName, thisLoader)),
superclassChain(thisClassName, thisLoader, [MethodClass | Rest]).
rewrittenUninitializedType(uninitialized(Address), Environment,
MethodClass, MethodClass) :-
allInstructions(Environment, Instructions),
member(instruction(Address, new(MethodClass)), Instructions).
rewrittenInitializationFlags(uninitializedThis, _Flags, []).
rewrittenInitializationFlags(uninitialized(_), Flags, Flags).
substitute(_Old, _New, [], []).
substitute(Old, New, [Old | FromRest], [New | ToRest]) :-
substitute(Old, New, FromRest, ToRest).
substitute(Old, New, [From1 | FromRest], [From1 | ToRest]) :-
From1 = Old,
substitute(Old, New, FromRest, ToRest).
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.
An invokestatic instruction is type safe iff all of the following are true:
-
Its first operand,
CP, refers to a constant pool entry denoting a method namedMethodNamewith descriptorDescriptor. -
One can validly replace types matching the argument types given in
Descriptoron the incoming operand stack with the return type given inDescriptor, yielding the outgoing type state.
instructionIsTypeSafe(invokestatic(CP), Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
CP = method(_MethodClassName, MethodName, Descriptor),
MethodName = '<init>',
MethodName = '<clinit>',
parseMethodDescriptor(Descriptor, OperandArgList, ReturnType),
reverse(OperandArgList, StackArgList),
validTypeTransition(Environment, StackArgList, ReturnType,
StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
An invokevirtual instruction is type safe iff all of the following are true:
-
Its first operand,
CP, refers to a constant pool entry denoting a method namedMethodNamewith descriptorDescriptorthat is a member of a classMethodClassName. -
One can validly replace types matching the class
MethodClassNameand the argument types given inDescriptoron the incoming operand stack with the return type given inDescriptor, yielding the outgoing type state. -
If the method is
protected, the usage conforms to the special rules governing access toprotectedmembers (§4.10.1.8).
instructionIsTypeSafe(invokevirtual(CP), Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
CP = method(MethodClassName, MethodName, Descriptor),
MethodName = '<init>',
MethodName = '<clinit>',
parseMethodDescriptor(Descriptor, OperandArgList, ReturnType),
reverse(OperandArgList, ArgList),
currentClassLoader(Environment, CurrentLoader),
reverse([class(MethodClassName, CurrentLoader) | OperandArgList],
StackArgList),
validTypeTransition(Environment, StackArgList, ReturnType,
StackFrame, NextStackFrame),
canPop(StackFrame, ArgList, PoppedFrame),
passesProtectedCheck(Environment, MethodClassName, MethodName,
Descriptor, PoppedFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
An ior instruction is type safe iff the equivalent iadd instruction is type safe.
instructionHasEquivalentTypeRule(ior, iadd).
An irem instruction is type safe iff the equivalent iadd instruction is type safe.
instructionHasEquivalentTypeRule(irem, iadd).
An ireturn instruction is type safe if the enclosing method has a declared return type of int, and one can validly pop a type matching int off the incoming operand stack.
instructionIsTypeSafe(ireturn, Environment, _Offset, StackFrame,
afterGoto, ExceptionStackFrame) :-
thisMethodReturnType(Environment, int),
canPop(StackFrame, [int], _PoppedStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
An ishl instruction is type safe iff the equivalent iadd instruction is type safe.
instructionHasEquivalentTypeRule(ishl, iadd).
An ishr instruction is type safe iff the equivalent iadd instruction is type safe.
instructionHasEquivalentTypeRule(ishr, iadd).
An iushr instruction is type safe iff the equivalent iadd instruction is type safe.
instructionHasEquivalentTypeRule(iushr, iadd).
An istore instruction with operand Index is type safe and yields an outgoing type state NextStackFrame, if a store instruction with operand Index and type int is type safe and yields an outgoing type state NextStackFrame.
instructionIsTypeSafe(istore(Index), Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
storeIsTypeSafe(Environment, Index, int, StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
The instructions istore_<n>, for 0 ≤ n ≤ 3, are type safe iff the equivalent istore instruction is type safe.
instructionHasEquivalentTypeRule(istore_0, istore(0)). instructionHasEquivalentTypeRule(istore_1, istore(1)). instructionHasEquivalentTypeRule(istore_2, istore(2)). instructionHasEquivalentTypeRule(istore_3, istore(3)).
An isub instruction is type safe iff the equivalent iadd instruction is type safe.
instructionHasEquivalentTypeRule(isub, iadd).
An ixor instruction is type safe iff the equivalent iadd instruction is type safe.
instructionHasEquivalentTypeRule(ixor, iadd).
An l2d instruction is type safe if one can validly pop long off the incoming operand stack and replace it with double, yielding the outgoing type state.
instructionIsTypeSafe(l2d, Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
validTypeTransition(Environment, [long], double,
StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
An l2f instruction is type safe if one can validly pop long off the incoming operand stack and replace it with float, yielding the outgoing type state.
instructionIsTypeSafe(l2f, Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
validTypeTransition(Environment, [long], float,
StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
An l2i instruction is type safe if one can validly pop long off the incoming operand stack and replace it with int, yielding the outgoing type state.
instructionIsTypeSafe(l2i, Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
validTypeTransition(Environment, [long], int,
StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
An ladd instruction is type safe iff one can validly replace types matching long and long on the incoming operand stack with long yielding the outgoing type state.
instructionIsTypeSafe(ladd, Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
validTypeTransition(Environment, [long, long], long,
StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
An laload instruction is type safe iff one can validly replace types matching int and array of long on the incoming operand stack with long yielding the outgoing type state.
instructionIsTypeSafe(laload, Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
validTypeTransition(Environment, [int, arrayOf(long)], long,
StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
An land instruction is type safe iff the equivalent ladd instruction is type safe.
instructionHasEquivalentTypeRule(land, ladd).
An lastore instruction is type safe iff one can validly pop types matching long, int and array of long off the incoming operand stack yielding the outgoing type state.
instructionIsTypeSafe(lastore, _Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
canPop(StackFrame, [long, int, arrayOf(long)], NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
A lcmp instruction is type safe iff one can validly replace types matching long and long on the incoming operand stack with int yielding the outgoing type state.
instructionIsTypeSafe(lcmp, Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
validTypeTransition(Environment, [long, long], int,
StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
An lconst_0 instruction is type safe if one can validly push the type long onto the incoming operand stack yielding the outgoing type state.
instructionIsTypeSafe(lconst_0, Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
validTypeTransition(Environment, [], long, StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
An lconst_1 instruction is type safe iff the equivalent lconst_0 instruction is type safe.
instructionHasEquivalentTypeRule(lconst_1, lconst_0).
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, class('java/lang/String', BL)],
[classConst, class('java/lang/Class', BL)],
[methodTypeConst, class('java/lang/invoke/MethodType', BL)],
[methodHandleConst, class('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).
An ldiv instruction is type safe iff the equivalent ladd instruction is type safe.
instructionHasEquivalentTypeRule(ldiv, ladd).
An lload instruction with operand Index is type safe and yields an outgoing type state NextStackFrame, if a load instruction with operand Index and type long is type safe and yields an outgoing type state NextStackFrame.
instructionIsTypeSafe(lload(Index), Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
loadIsTypeSafe(Environment, Index, long, StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
The instructions lload_<n>, for 0 ≤ n ≤ 3, are type safe iff the equivalent lload instruction is type safe.
instructionHasEquivalentTypeRule(lload_0, lload(0)). instructionHasEquivalentTypeRule(lload_1, lload(1)). instructionHasEquivalentTypeRule(lload_2, lload(2)). instructionHasEquivalentTypeRule(lload_3, lload(3)).
An lmul instruction is type safe iff the equivalent ladd instruction is type safe.
instructionHasEquivalentTypeRule(lmul, ladd).
An lneg instruction is type safe iff there is a type matching long on the incoming operand stack. The lneg instruction does not alter the type state.
instructionIsTypeSafe(lneg, Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
validTypeTransition(Environment, [long], long,
StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
A lookupswitch instruction is type safe if its keys are sorted, one can validly pop int off the incoming operand stack yielding a new type state BranchStackFrame, and all of the instruction's targets are valid branch targets assuming BranchStackFrame as their incoming type state.
instructionIsTypeSafe(lookupswitch(Targets, Keys), Environment, _, StackFrame,
afterGoto, ExceptionStackFrame) :-
sort(Keys, Keys),
canPop(StackFrame, [int], BranchStackFrame),
checklist(targetIsTypeSafe(Environment, BranchStackFrame), Targets),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
A lor instruction is type safe iff the equivalent ladd instruction is type safe.
instructionHasEquivalentTypeRule(lor, ladd).
An lrem instruction is type safe iff the equivalent ladd instruction is type safe.
instructionHasEquivalentTypeRule(lrem, ladd).
An lreturn instruction is type safe if the enclosing method has a declared return type of long, and one can validly pop a type matching long off the incoming operand stack.
instructionIsTypeSafe(lreturn, Environment, _Offset, StackFrame,
afterGoto, ExceptionStackFrame) :-
thisMethodReturnType(Environment, long),
canPop(StackFrame, [long], _PoppedStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
An lshl instruction is type safe if one can validly replace the types int and long on the incoming operand stack with the type long yielding the outgoing type state.
instructionIsTypeSafe(lshl, Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
validTypeTransition(Environment, [int, long], long,
StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
An lshr instruction is type safe iff the equivalent lshl instruction is type safe.
instructionHasEquivalentTypeRule(lshr, lshl).
An lushr instruction is type safe iff the equivalent lshl instruction is type safe.
instructionHasEquivalentTypeRule(lushr, lshl).
An lstore instruction with operand Index is type safe and yields an outgoing type state NextStackFrame, if a store instruction with operand Index and type long is type safe and yields an outgoing type state NextStackFrame.
instructionIsTypeSafe(lstore(Index), Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
storeIsTypeSafe(Environment, Index, long, StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
The instructions lstore_<n>, for 0 ≤ n ≤ 3, are type safe iff the equivalent lstore instruction is type safe.
instructionHasEquivalentTypeRule(lstore_0, lstore(0)). instructionHasEquivalentTypeRule(lstore_1, lstore(1)). instructionHasEquivalentTypeRule(lstore_2, lstore(2)). instructionHasEquivalentTypeRule(lstore_3, lstore(3)).
An lsub instruction is type safe iff the equivalent ladd instruction is type safe.
instructionHasEquivalentTypeRule(lsub, ladd).
An lxor instruction is type safe iff the equivalent ladd instruction is type safe.
instructionHasEquivalentTypeRule(lxor, ladd).
A monitorenter instruction is type safe iff one can validly pop a type matching reference off the incoming operand stack yielding the outgoing type state.
instructionIsTypeSafe(monitorenter, _Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
canPop(StackFrame, [reference], NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
A monitorexit instruction is type safe iff the equivalent monitorenter instruction is type safe.
instructionHasEquivalentTypeRule(monitorexit, monitorenter).
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) :-
CP = arrayOf(_),
classDimension(CP, Dimension),
Dimension >= Dim,
Dim > 0,
/* Make a list of Dim ints */
findall(int, between(1, Dim, _), IntList),
validTypeTransition(Environment, IntList, CP,
StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
The dimension of an array type whose component type is also an array type is one more than the dimension of its component type.
classDimension(arrayOf(X), Dimension) :-
classDimension(X, Dimension1),
Dimension is Dimension1 + 1.
classDimension(_, Dimension) :-
Dimension = 0.
A new instruction with operand CP at offset Offset is type safe iff CP refers to a constant pool entry denoting a class or interface 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 (§invokespecial).
A newarray instruction with operand TypeCode is type safe iff TypeCode corresponds to the primitive type ElementType, and one can validly replace the type int on the incoming operand stack with the type 'array of ElementType', yielding the outgoing type state.
instructionIsTypeSafe(newarray(TypeCode), Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
primitiveArrayInfo(TypeCode, _TypeChar, ElementType, _VerifierType),
validTypeTransition(Environment, [int], arrayOf(ElementType),
StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
The correspondence between type codes and primitive types is specified by the following predicate:
primitiveArrayInfo(4, 0'Z, boolean, int). primitiveArrayInfo(5, 0'C, char, int). primitiveArrayInfo(6, 0'F, float, float). primitiveArrayInfo(7, 0'D, double, double). primitiveArrayInfo(8, 0'B, byte, int). primitiveArrayInfo(9, 0'S, short, int). primitiveArrayInfo(10, 0'I, int, int). primitiveArrayInfo(11, 0'J, long, long).
A nop instruction is always type safe. The nop instruction does not affect the type state.
instructionIsTypeSafe(nop, _Environment, _Offset, StackFrame,
StackFrame, ExceptionStackFrame) :-
exceptionStackFrame(StackFrame, ExceptionStackFrame).
A pop instruction is type safe iff one can validly pop a category 1 type off the incoming operand stack yielding the outgoing type state.
instructionIsTypeSafe(pop, _Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
StackFrame = frame(Locals, [Type | Rest], Flags),
popCategory1([Type | Rest], Type, Rest),
NextStackFrame = frame(Locals, Rest, Flags),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
A pop2 instruction is type safe iff it is a type safe form of the pop2 instruction.
instructionIsTypeSafe(pop2, _Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
StackFrame = frame(Locals, InputOperandStack, Flags),
pop2SomeFormIsTypeSafe(InputOperandStack, OutputOperandStack),
NextStackFrame = frame(Locals, OutputOperandStack, Flags),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
A pop2 instruction is a type safe form of the pop2 instruction iff it is a type safe form 1 pop2 instruction or a type safe form 2 pop2 instruction.
pop2SomeFormIsTypeSafe(InputOperandStack, OutputOperandStack) :-
pop2Form1IsTypeSafe(InputOperandStack, OutputOperandStack).
pop2SomeFormIsTypeSafe(InputOperandStack, OutputOperandStack) :-
pop2Form2IsTypeSafe(InputOperandStack, OutputOperandStack).
A pop2 instruction is a type safe form 1 pop2 instruction iff one can validly pop two types of size 1 off the incoming operand stack yielding the outgoing type state.
pop2Form1IsTypeSafe([Type1, Type2 | Rest], Rest) :-
popCategory1([Type1 | Rest], Type1, Rest),
popCategory1([Type2 | Rest], Type2, Rest).
A pop2 instruction is a type safe form 2 pop2 instruction iff one can validly pop a type of size 2 off the incoming operand stack yielding the outgoing type state.
pop2Form2IsTypeSafe([top, Type | Rest], Rest) :-
popCategory2([top, Type | Rest], Type, Rest).
A putfield instruction with operand CP is type safe iff all of the following are true:
-
Its first operand,
CP, refers to a constant pool entry denoting a field whose declared type isFieldType, declared in a classFieldClassName.FieldClassNamemust not be an array type. -
-
One can validly pop types matching
FieldTypeandFieldClassNameoff the incoming operand stack yielding the outgoing type state. -
protectedfields are subject to additional checks (§4.10.1.8).
-
instructionIsTypeSafe(putfield(CP), Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
CP = field(FieldClassName, FieldName, FieldDescriptor),
parseFieldDescriptor(FieldDescriptor, FieldType),
canPop(StackFrame, [FieldType], PoppedFrame),
passesProtectedCheck(Environment, FieldClassName, FieldName,
FieldDescriptor, PoppedFrame),
currentClassLoader(Environment, CurrentLoader),
canPop(StackFrame, [FieldType, class(FieldClassName, CurrentLoader)],
NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
-
-
If the instruction occurs in an instance initialization method of the class
FieldClassName, then one can validly pop types matchingFieldTypeanduninitializedThisoff the incoming operand stack yielding the outgoing type state. This allows instance fields ofthisthat are declared in the current class to be assigned prior to complete initialization ofthis.
-
instructionIsTypeSafe(putfield(CP), Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
CP = field(FieldClassName, _FieldName, FieldDescriptor),
parseFieldDescriptor(FieldDescriptor, FieldType),
Environment = environment(CurrentClass, CurrentMethod, _, _, _, _),
CurrentClass = class(FieldClassName, _),
isInit(CurrentMethod),
canPop(StackFrame, [FieldType, uninitializedThis], NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
A putstatic instruction with operand CP is type safe iff CP refers to a constant pool entry denoting a field whose declared type is FieldType, and one can validly pop a type matching FieldTypeoff the incoming operand stack yielding the outgoing type state.
instructionIsTypeSafe(putstatic(CP), _Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
CP = field(_FieldClassName, _FieldName, FieldDescriptor),
parseFieldDescriptor(FieldDescriptor, FieldType),
canPop(StackFrame, [FieldType], NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
A return instruction is type safe if the enclosing method declares a void return type, and either:
instructionIsTypeSafe(return, Environment, _Offset, StackFrame,
afterGoto, ExceptionStackFrame) :-
thisMethodReturnType(Environment, void),
StackFrame = frame(_Locals, _OperandStack, Flags),
notMember(flagThisUninit, Flags),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
An saload instruction is type safe iff one can validly replace types matching int and array of short on the incoming operand stack with int yielding the outgoing type state.
instructionIsTypeSafe(saload, Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
validTypeTransition(Environment, [int, arrayOf(short)], int,
StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
An sastore instruction is type safe iff one can validly pop types matching int, int, and array of short off the incoming operand stack yielding the outgoing type state.
instructionIsTypeSafe(sastore, _Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
canPop(StackFrame, [int, int, arrayOf(short)], NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
An sipush instruction is type safe iff one can validly push the type int onto the incoming operand stack yielding the outgoing type state.
instructionIsTypeSafe(sipush(_Value), Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
validTypeTransition(Environment, [], int, StackFrame, NextStackFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
A swap instruction is type safe iff one can validly replace two category 1 types, Type1 and Type2, on the incoming operand stack with the types Type2 and Type1 yielding the outgoing type state.
instructionIsTypeSafe(swap, _Environment, _Offset, StackFrame,
NextStackFrame, ExceptionStackFrame) :-
StackFrame = frame(_Locals, [Type1, Type2 | Rest], _Flags),
popCategory1([Type1 | Rest], Type1, Rest),
popCategory1([Type2 | Rest], Type2, Rest),
NextStackFrame = frame(_Locals, [Type2, Type1 | Rest], _Flags),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
A tableswitch instruction is type safe if its keys are sorted, one can validly pop int off the incoming operand stack yielding a new type state BranchStackFrame, and all of the instruction's targets are valid branch targets assuming BranchStackFrame as their incoming type state.
instructionIsTypeSafe(tableswitch(Targets, Keys), Environment, _Offset,
StackFrame, afterGoto, ExceptionStackFrame) :-
sort(Keys, Keys),
canPop(StackFrame, [int], BranchStackFrame),
checklist(targetIsTypeSafe(Environment, BranchStackFrame), Targets),
exceptionStackFrame(StackFrame, ExceptionStackFrame).
A class file that does not contain a StackMapTable attribute (which necessarily has a version number of 49.0 or below) must be verified using type inference.
During linking, the verifier checks the code array of the Code attribute for each method of the class file by performing data-flow analysis on each method. The verifier ensures that at any given point in the program, no matter what code path is taken to reach that point, all of the following are true:
For efficiency reasons, certain tests that could in principle be performed by the verifier are delayed until the first time the code for the method is actually invoked. In so doing, the verifier avoids loading class files unless it has to.
For example, if a method invokes another method that returns an instance of class A, and that instance is assigned only to a field of the same type, the verifier does not bother to check if the class A actually exists. However, if it is assigned to a field of the type B, the definitions of both A and B must be loaded in to ensure that A is a subclass of B.
The code for each method is verified independently. First, the bytes that make up the code are broken up into a sequence of instructions, and the index into the code array of the start of each instruction is placed in an array. The verifier then goes through the code a second time and parses the instructions. During this pass a data structure is built to hold information about each Java Virtual Machine instruction in the method. The operands, if any, of each instruction are checked to make sure they are valid. For instance:
-
Branches must be within the bounds of the
codearray for the method. -
The targets of all control-flow instructions are each the start of an instruction. In the case of a wide instruction, the wide opcode is considered the start of the instruction, and the opcode giving the operation modified by that wide instruction is not considered to start an instruction. Branches into the middle of an instruction are disallowed.
-
No instruction can access or modify a local variable at an index greater than or equal to the number of local variables that its method indicates it allocates.
-
All references to the constant pool must be to an entry of the appropriate type. (For example, the instruction getfield must reference a field.)
-
For each exception handler, the starting and ending point of code protected by the handler must be at the beginning of an instruction or, in the case of the ending point, immediately past the end of the code. The starting point must be before the ending point. The exception handler code must start at a valid instruction, and it must not start at an opcode being modified by the wideinstruction.
For each instruction of the method, the verifier records the contents of the operand stack and the contents of the local variable array prior to the execution of that instruction. For the operand stack, it needs to know the stack height and the type of each value on it. For each local variable, it needs to know either the type of the contents of that local variable or that the local variable contains an unusable or unknown value (it might be uninitialized). The bytecode verifier does not need to distinguish between the integral types (e.g., byte, short, char) when determining the value types on the operand stack.
Next, a data-flow analyzer is initialized. For the first instruction of the method, the local variables that represent parameters initially contain values of the types indicated by the method's type descriptor; the operand stack is empty. All other local variables contain an illegal value. For the other instructions, which have not been examined yet, no information is available regarding the operand stack or local variables.
Finally, the data-flow analyzer is run. For each instruction, a "changed" bit indicates whether this instruction needs to be looked at. Initially, the "changed" bit is set only for the first instruction. The data-flow analyzer executes the following loop:
-
Select a Java Virtual Machine instruction whose "changed" bit is set. If no instruction remains whose "changed" bit is set, the method has successfully been verified. Otherwise, turn off the "changed" bit of the selected instruction.
-
Model the effect of the instruction on the operand stack and local variable array by doing the following:
-
If the instruction uses values from the operand stack, ensure that there are a sufficient number of values on the stack and that the top values on the stack are of an appropriate type. Otherwise, verification fails.
-
If the instruction uses a local variable, ensure that the specified local variable contains a value of the appropriate type. Otherwise, verification fails.
-
If the instruction pushes values onto the operand stack, ensure that there is sufficient room on the operand stack for the new values. Add the indicated types to the top of the modeled operand stack.
-
If the instruction modifies a local variable, record that the local variable now contains the new type.
-
-
Determine the instructions that can follow the current instruction. Successor instructions can be one of the following:
-
Merge the state of the operand stack and local variable array at the end of the execution of the current instruction into each of the successor instructions, as follows:
-
If this is the first time the successor instruction has been visited, record that the operand stack and local variable values calculated in step 2 are the state of the operand stack and local variable array prior to executing the successor instruction. Set the "changed" bit for the successor instruction.
-
If the successor instruction has been seen before, merge the operand stack and local variable values calculated in step 2 into the values already there. Set the "changed" bit if there is any modification to the values.
In the special case of control transfer to an exception handler:
-
Record that a single object, of the exception type indicated by the exception handler, is the state of the operand stack prior to executing the successor instruction. There must be sufficient room on the operand stack for this single value, as if an instruction had pushed it.
-
Record that the local variable values from immediately before step 2 are the state of the local variable array prior to executing the successor instruction. The local variable values calculated in step 2 are irrelevant.
-
To merge two operand stacks, the number of values on each stack must be identical. Then, corresponding values on the two stacks are compared and the value on the merged stack is computed, as follows:
-
If one value is a primitive type, then the corresponding value must be the same primitive type. The merged value is the primitive type.
-
If one value is a non-array reference type, then the corresponding value must be a reference type (array or non-array). The merged value is a reference to an instance of the first common supertype of the two reference types. (Such a reference type always exists because the type
Objectis a supertype of all class, interface, and array types.)For example,
ObjectandStringcan be merged; the result isObject. Similarly,ObjectandString[]can be merged; the result is againObject. EvenObjectandint[]can be merged, orStringandint[]; the result isObjectfor both. -
If corresponding values are both array reference types, then their dimensions are examined. If the array types have the same dimensions, then the merged value is a
referenceto an instance of an array type which is first common supertype of both array types. (If either or both of the array types has a primitive element type, thenObjectis used as the element type instead.) If the array types have different dimensions, then the merged value is areferenceto an instance of an array type whose dimension is the smaller of the two; the element type isCloneableorjava.io.Serializableif the smaller array type wasCloneableorjava.io.Serializable, andObjectotherwise.For example,
Object[]andString[]can be merged; the result isObject[].Cloneable[]andString[]can be merged, orjava.io.Serializable[]andString[]; the result isCloneable[]andjava.io.Serializable[]respectively. Evenint[]andString[]can be merged; the result isObject[], becauseObjectis used instead ofintwhen computing the first common supertype.Since the array types can have different dimensions,
Object[]andString[][]can be merged, orObject[][]andString[]; in both cases the result isObject[].Cloneable[]andString[][]can be merged; the result isCloneable[]. Finally,Cloneable[][]andString[]can be merged; the result isObject[].
If the operand stacks cannot be merged, verification of the method fails.
To merge two local variable array states, corresponding pairs of local variables are compared. The value of the merged local variable is computed using the rules above, except that the corresponding values are permitted to be different primitive types. In that case, the verifier records that the merged local variable contains an unusable value.
If the data-flow analyzer runs on a method without reporting a verification failure, then the method has been successfully verified by the class file verifier.
Certain instructions and data types complicate the data-flow analyzer. We now examine each of these in more detail.
Values of the long and double types are treated specially by the verification process.
Whenever a value of type long or double is moved into a local variable at index n, index n+1 is specially marked to indicate that it has been reserved by the value at index n and must not be used as a local variable index. Any value previously at index n+1 becomes unusable.
Whenever a value is moved to a local variable at index n, the index n-1 is examined to see if it is the index of a value of type long or double. If so, the local variable at index n-1 is changed to indicate that it now contains an unusable value. Since the local variable at index n has been overwritten, the local variable at index n-1 cannot represent a value of type long or double.
Dealing with values of types long or double on the operand stack is simpler; the verifier treats them as single values on the stack. For example, the verification code for the dadd opcode (add two double values) checks that the top two items on the stack are both of type double. When calculating operand stack length, values of type long and double have length two.
Untyped instructions that manipulate the operand stack must treat values of type long and double as atomic (indivisible). For example, the verifier reports a failure if the top value on the stack is a double and it encounters an instruction such as pop or dup. The instructions pop2 or dup2 must be used instead.
Creating a new class instance is a multistep process. The statement:
... new myClass(i, j, k); ...
can be implemented by the following:
...
new #1 // Allocate uninitialized space for myClass
dup // Duplicate object on the operand stack
iload_1 // Push i
iload_2 // Push j
iload_3 // Push k
invokespecial #5 // Invoke myClass.<init>
...
This instruction sequence leaves the newly created and initialized object on top of the operand stack. (Additional examples of compilation to the instruction set of the Java Virtual Machine are given in §3 (Compiling for the Java Virtual Machine).)
The instance initialization method (§2.9.1) for class myClass sees the new uninitialized object as its this argument in local variable 0. Before that method invokes another instance initialization method of myClass or its direct superclass on this, the only operation the method can perform on this is assigning fields declared within myClass.
When doing dataflow analysis on instance methods, the verifier initializes local variable 0 to contain an object of the current class, or, for instance initialization methods, local variable 0 contains a special type indicating an uninitialized object. After an appropriate instance initialization method is invoked (from the current class or its direct superclass) on this object, all occurrences of this special type on the verifier's model of the operand stack and in the local variable array are replaced by the current class type. The verifier rejects code that uses the new object before it has been initialized or that initializes the object more than once. In addition, it ensures that every normal return of the method has invoked an instance initialization method either in the class of this method or in the direct superclass.
Similarly, a special type is created and pushed on the verifier's model of the operand stack as the result of the Java Virtual Machine instruction new. The special type indicates the instruction by which the class instance was created and the type of the uninitialized class instance created. When an instance initialization method declared in the class of the uninitialized class instance is invoked on that class instance, all occurrences of the special type are replaced by the intended type of the class instance. This change in type may propagate to subsequent instructions as the dataflow analysis proceeds.
The instruction number needs to be stored as part of the special type, as there may be multiple not-yet-initialized instances of a class in existence on the operand stack at one time. For example, the Java Virtual Machine instruction sequence that implements:
new InputStream(new Foo(), new InputStream("foo"))
may have two uninitialized instances of InputStream on the operand stack at once. When an instance initialization method is invoked on a class instance, only those occurrences of the special type on the operand stack or in the local variable array that are the same object as the class instance are replaced.
To implement the try-finally construct, a compiler for the Java programming language that generates class files with version number 50.0 or below may use the exception-handling facilities together with two special instructions: jsr ("jump to subroutine") and ret ("return from subroutine"). The finally clause is compiled as a subroutine within the Java Virtual Machine code for its method, much like the code for an exception handler. When a jsr instruction that invokes the subroutine is executed, it pushes its return address, the address of the instruction after the jsr that is being executed, onto the operand stack as a value of type returnAddress. The code for the subroutine stores the return address in a local variable. At the end of the subroutine, a ret instruction fetches the return address from the local variable and transfers control to the instruction at the return address.
Control can be transferred to the finally clause (the finally subroutine can be invoked) in several different ways. If the try clause completes normally, the finally subroutine is invoked via a jsr instruction before evaluating the next expression. A break or continue inside the try clause that transfers control outside the try clause executes a jsr to the code for the finally clause first. If the try clause executes a return, the compiled code does the following:
The compiler sets up a special exception handler, which catches any exception thrown by the try clause. If an exception is thrown in the try clause, this exception handler does the following:
For more information about the implementation of the try-finally construct, see §3.13.
The code for the finally clause presents a special problem to the verifier. Usually, if a particular instruction can be reached via multiple paths and a particular local variable contains incompatible values through those multiple paths, then the local variable becomes unusable. However, a finally clause might be called from several different places, yielding several different circumstances:
-
The invocation from the exception handler may have a certain local variable that contains an exception.
-
The invocation to implement return may have some local variable that contains the return value.
-
The invocation from the bottom of the
tryclause may have an indeterminate value in that same local variable.
The code for the finally clause itself might pass verification, but after completing the updating all the successors of the ret instruction, the verifier would note that the local variable that the exception handler expects to hold an exception, or that the return code expects to hold a return value, now contains an indeterminate value.
Verifying code that contains a finally clause is complicated. The basic idea is the following:
-
Each instruction keeps track of the list of jsr targets needed to reach that instruction. For most code, this list is empty. For instructions inside code for the
finallyclause, it is of length one. For multiply nestedfinallycode (extremely rare!), it may be longer than one. -
For each instruction and each jsr needed to reach that instruction, a bit vector is maintained of all local variables accessed or modified since the execution of the jsr instruction.
-
When executing the ret instruction, which implements a return from a subroutine, there must be only one possible subroutine from which the instruction can be returning. Two different subroutines cannot "merge" their execution to a single ret instruction.
-
To perform the data-flow analysis on a ret instruction, a special procedure is used. Since the verifier knows the subroutine from which the instruction must be returning, it can find all the jsrinstructions that call the subroutine and merge the state of the operand stack and local variable array at the time of the ret instruction into the operand stack and local variable array of the instructions following the jsr. Merging uses a special set of values for local variables:
The following limitations of the Java Virtual Machine are implicit in the class file format:
-
The per-class or per-interface constant pool is limited to 65535 entries by the 16-bit
constant_pool_countfield of theClassFilestructure (§4.1). This acts as an internal limit on the total complexity of a single class or interface. -
The number of fields that may be declared by a class or interface is limited to 65535 by the size of the
fields_countitem of theClassFilestructure (§4.1).Note that the value of the
fields_countitem of theClassFilestructure does not include fields that are inherited from superclasses or superinterfaces. -
The number of methods that may be declared by a class or interface is limited to 65535 by the size of the
methods_countitem of theClassFilestructure (§4.1).Note that the value of the
methods_countitem of theClassFilestructure does not include methods that are inherited from superclasses or superinterfaces. -
The number of direct superinterfaces of a class or interface is limited to 65535 by the size of the
interfaces_countitem of theClassFilestructure (§4.1). -
The greatest number of local variables in the local variables array of a frame created upon invocation of a method (§2.6) is limited to 65535 by the size of the
max_localsitem of theCodeattribute (§4.7.3) giving the code of the method, and by the 16-bit local variable indexing of the Java Virtual Machine instruction set.Note that values of type
longanddoubleare each considered to reserve two local variables and contribute two units toward themax_localsvalue, so use of local variables of those types further reduces this limit. -
The size of an operand stack in a frame (§2.6) is limited to 65535 values by the
max_stackfield of theCodeattribute (§4.7.3).Note that values of type
longanddoubleare each considered to contribute two units toward themax_stackvalue, so use of values of these types on the operand stack further reduces this limit. -
The number of method parameters is limited to 255 by the definition of a method descriptor (§4.3.3), where the limit includes one unit for
thisin the case of instance or interface method invocations.Note that a method descriptor is defined in terms of a notion of method parameter length in which a parameter of type
longordoublecontributes two units to the length, so parameters of these types further reduce the limit. -
The length of field and method names, field and method descriptors, and other constant string values (including those referenced by
ConstantValue(§4.7.2) attributes) is limited to 65535 characters by the 16-bit unsignedlengthitem of theCONSTANT_Utf8_infostructure (§4.4.7).Note that the limit is on the number of bytes in the encoding and not on the number of encoded characters. UTF-8 encodes some characters using two or three bytes. Thus, strings incorporating multibyte characters are further constrained.
-
The number of dimensions in an array is limited to 255 by the size of the dimensions opcode of the multianewarray instruction and by the constraints imposed on the multianewarray, anewarray, and newarray instructions (§4.9.1, §4.9.2).