This document proposes changes to the Java Virtual Machine Specification to allow access to private class members from related "nestmate" classes. See JEP 181 for an overview.

There are two major changes:

  1. Introducing the NestMembers and MemberOfNest attributes, and specifying how they should be validated. Modifying the accessibility rules so that private members within a nest can be referenced.

  2. Modifying the validation rules for invokespecial so that private methods can be referenced outside of the current class and its supertypes. Accompanied by cleanups in the treatment of protected members, mainly for improved presentation.

3.7 Invoking Methods

...

Note that superclass methods called using the invokespecial instruction always pass this to the invoked method as its first argument. As usual, it is received in local variable 0.

This assertion is wrong about private methods: it has always been allowed to invoke a private method of a different class instance (an object other than this). Further, now a private method of a different class can be invoked directly in the bytecode.

...

4.7 Attributes

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

All attributes have the following general format:

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

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

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

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

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

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

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

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

    The Exceptions attribute merely lists the declared throws clause of a method. This feature is specific to the Java language, and (I believe?) doesn't impact JVM behavior at all.

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

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

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

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

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

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

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

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

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
NestMembers ClassFile 54.0
MemberOfNest ClassFile 54.0
ConstantValue field_info 45.3
Code method_info 45.3
Exceptions method_info 45.3
RuntimeVisibleParameterAnnotations, RuntimeInvisibleParameterAnnotations method_info 49.0
AnnotationDefault method_info 49.0
MethodParameters method_info 52.0
Synthetic ClassFile, field_info, method_info 45.3
Deprecated ClassFile, field_info, method_info 45.3
Signature ClassFile, field_info, method_info 49.0
RuntimeVisibleAnnotations, RuntimeInvisibleAnnotations ClassFile, field_info, method_info 49.0
LineNumberTable Code 45.3
LocalVariableTable Code 45.3
LocalVariableTypeTable Code 49.0
StackMapTable Code 50.0
RuntimeVisibleTypeAnnotations, RuntimeInvisibleTypeAnnotations ClassFile, field_info, method_info, Code 52.0

4.7.25 The NestMembers Attribute

The NestMembers attribute is a variable-length attribute in the attributes table of a ClassFile structure (4.1). It defines a nest, a set of classes and interfaces that share access to private members (5.4.4). A class with a NestMembers attribute is the host class of the nest.

There may be at most one NestMembers attribute in the attributes table of a ClassFile structure.

The NestMembers attribute has the following format:

NestMembers_attribute { 
    u2 attribute_name_index; 
    u4 attribute_length; 
    u2 number_of_classes;
    u2 classes[number_of_classes]; 
}

The items of the NestMembers_attribute structure are as follows:

attribute_name_index

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

attribute_length

The value of the attribute_length item indicates the length of the attribute, excluding the initial six bytes.

number_of_classes

The value of the number_of_classes item indicates the number of entries in the classes array.

classes[]

Each value in the classes array must be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_Class_info structure (4.4.1) representing a class or interface.

4.7.26 The MemberOfNest Attribute

The MemberOfNest attribute is a fixed-length attribute in the attributes table of a ClassFile structure (4.1). A class or interface with a MemberOfNest attribute claims membership in a nest hosted by the referenced class or interface (4.7.25).

There may be at most one MemberOfNest attribute in the attributes table of a ClassFile structure.

The attributes table of a ClassFile structure must not contain both a MemberOfNest attribute and a NestMembers attribute.

If the attributes table of a ClassFile structure does not contain a MemberOfNest attribute, the class is implicitly a member of its own nest (5.4.4).

The MemberOfNest attribute has the following format:

MemberOfNest_attribute { 
    u2 attribute_name_index; 
    u4 attribute_length; 
    u2 host_class_index; 
}

The items of the MemberOfNest_attribute structure are as follows:

attribute_name_index

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

attribute_length

The value of the attribute_length item must be two.

host_class_index

The value of the host_class_index item must be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_Class_info structure (4.4.1) representing a class or interface.

4.9.2 Structural Constraints

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

...

...

...

4.10 Verification of class Files

...

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 four additional checks outside the Code attribute which must be performed during verification:

There are at least three options for checking NestMembers and MemberOfNest attributes:

We opt to use the second approach here to ensure a MemberOfNest attribute always references a host class in its same package with a supporting NestMembers attribute.

We opt to use the third approach when a NestMembers attribute lists a class that does not have a supporting MemberOfNest attribute (5.4.4): both the host class and the claimed member class will load and link without error, and an error will only occur when another nest member attempts to access a private member. This allows verification to proceed without loading every class mentioned by a NestMembers attribute.

4.10.1 Verification by Type Checking

...

A class is type safe if all its methods are type safe, and it does not subclass a final class, and if it claims to belong to a nest, the referenced host class is in the same package and includes the class in its list of nest members.

classIsTypeSafe(Class) :-

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

classIsTypeSafe(Class) :-

classClassName(Class, 'java/lang/Object'),
classDefiningLoader(Class, L),
isBootstrapLoader(L),
classHasValidNest(Class),
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 classHasValidNest predicate checks the MemberOfNest attribute of a class, as follows:

classHasValidNest(Class) :-

\+ classMemberOfNestName(Class, _).

classHasValidNest(Class) :-

classMemberOfNestName(Class, HostName),
classDefiningLoader(Class, L1),
loadedClass(HostName, L1, HostClass),
samePackageName(Class, HostClass),
classClassName(Class, Name),
classNestMemberNames(HostClass, MemberNames),
member(Name, MemberNames),
classDefiningLoader(HostClass, L2),
loadedClass(Name, L2, Class).

The rest of this section explains the process of type checking in detail:

...

4.10.1.1 Accessors for Java Virtual Machine Artifacts

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

classClassName(Class, ClassName)

Extracts the name, ClassName, of the class Class.

classIsInterface(Class)

True iff the class, Class, is an interface.

classIsNotFinal(Class)

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

classSuperClassName(Class, SuperClassName)

Extracts the name, SuperClassName, of the superclass of class Class.

classInterfaces classInterfaceNames(Class, Interfaces InterfaceNames)

Extracts a list, InterfaceNames, of the names of the direct superinterfaces of the class Class.

classMethods(Class, Methods)

Extracts a list, Methods, of the methods declared in the class Class.

classNestMemberNames(Class, MemberNames)

Extracts a list, MemberNames, of the nest members identified by a NestMembers attribute of the class Class (4.7.25).

classMemberOfNestName(Class, HostClassName)

Extracts the name, HostClassName, of the host class identified by a MemberOfNest attribute of the class Class (4.7.26).

classAttributes(Class, Attributes)

Extracts a list, Attributes, of the attributes of the class Class.

Each attribute is represented as a functor application of the form attribute(AttributeName, AttributeContents), where AttributeName is the name of the attribute. The format of the attribute's contents is unspecified.

This predicate is never used.

classDefiningLoader(Class, Loader)

Extracts the defining class loader, Loader, of the class Class.

isBootstrapLoader(Loader)

True iff the class loader Loader is the bootstrap class loader.

loadedClass(Name, InitiatingLoader, ClassDefinition)

True iff there exists a class named Name whose representation (in accordance with this specification) when loaded by the class loader InitiatingLoader is ClassDefinition.

loadedClasses(Names, InitiatingLoader, ClassDefinitions)

Applies loadedClass to a list of class names.

methodName(Method, Name)

Extracts the name, Name, of the method Method.

methodAccessFlags(Method, AccessFlags)

Extracts the access flags, AccessFlags, of the method Method.

methodDescriptor(Method, Descriptor)

Extracts the descriptor, Descriptor, of the method Method.

methodAttributes(Method, Attributes)

Extracts a list, Attributes, of the attributes of the method Method.

Each attribute is represented as a functor application of the form attribute(AttributeName, AttributeContents), where AttributeName is the name of the attribute. The format of the attribute's contents is unspecified.

isInit(Method)

True iff Method (regardless of class) is named <init>.

isNotInit(Method)

True iff Method (regardless of class) is not named <init>.

isNotFinal(Method, Class)

True iff Method in class Class is not final.

isStatic(Method, Class)

True iff Method in class Class is static.

isNotStatic(Method, Class)

True iff Method in class Class is not static.

isPrivate(Method, Class)

True iff Method in class Class is private.

isNotPrivate(Method, Class)

True iff Method in class Class is not private.

isProtected(MemberClass, MemberName, MemberDescriptor)

True iff there is a member named MemberName with descriptor MemberDescriptor in the class MemberClass and it is protected.

isNotProtected(MemberClass, MemberName, MemberDescriptor)

True iff there is a member named MemberName with descriptor MemberDescriptor in the class MemberClass and it is not protected.

isProtected(Member, Class)

True iff Member in class Class is protected.

isNotProtected(Member, Class)

True iff Member in class Class is not protected.

resolvedMember(ReferencedClass, MemberName, MemberDescriptor, DeclaringClass, Member)

Given a symbolic reference to a field or method in class ReferencedClass named MemberName with descriptor MemberDescriptor, identifies the field or method Member declared in class DeclaringClass that would be produced by the resolution algorithm of 5.4.3.2, 5.4.3.3, or 5.4.3.4.

parseFieldDescriptor(Descriptor, Type)

Converts a field descriptor, Descriptor, into the corresponding verification type Type (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 method Method in Class, as well as the maximum operand stack size, MaxStack, the maximal number of local variables, FrameSize, the exception handlers, Handlers, and the stack map StackMap.

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

samePackageName(Class1, Class2)

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

differentPackageName(Class1, Class2)

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

...

4.10.1.8 Type Checking for protected Members Restricted Member References

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

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

The getfield, putfield, and invokevirtual instructions may be used to access a protected member declared in a different package, but only if the member is referenced via the current class, a superclass of the current class, or a subclass of the current class; and only if the type of the target reference is assignable to the type of the current class.

Similarly, the invokespecial instruction may be used to invoke a non-private, non-<init> method only if the the method is referenced via the current class, a superclass of the current class, or a direct superinterface of the current class; and only if the type of the target reference is assignable to the type of the current class.

In both cases, the restriction on the referenced class is enforced after resolution (getfield, putfield, invokevirtual, invokespecial). But the restriction on the type of the target reference must be enforced by the verifier.

Rather than resolving every referenced member in order to check its access flags, the verifier limits its checks to cases in which the name of the referenced class matches a superclass or superinterface. In any other case, either i) the referenced class is not one of the supported classes, and an error will occur after resolution, or ii) the referenced class is the current class or a subclass of the current class, and verification will already ensure that the type of the target reference is assignable to that class.

While the treatment of protected instance method invocations is slightly different from the treatment of non-private invokespecial method invocations, the ultimate goal—checking in some circumstances that the type on the stack is a subtype of the current class—is the same. So it's helpful to describe both of these checks at the same time.

There are a number of technical problems with the existing passesProtectedCheck rule, and it's not clear how closely the specified rule aligns with implementation behavior. The rule is rewritten here to address these problems and improve clarity. If any inconsistencies with longstanding implementation behavior are observed, the rewritten rule can be revised.

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).

A member reference is a restricted protected reference if the referenced class is a superclass of the current class, the member is declared protected, and the member is declared in a different package than the current class.

restrictedProtectedReference(CurrentClass, MemberClassName, MemberName, MemberDescriptor) :-

CurrentClass = class(CurrentClassName, CurrentLoader),
superclassChain(CurrentClassName, CurrentLoader, Chain),
member(class(MemberClassName, _), Chain),
loadedClass(MemberClassName, CurrentLoader, ReferencedClass),
member(ReferencedClass, Chain),
resolvedMember(ReferencedClass, MemberName, MemberDescriptor, DeclaringClass, Member),
isProtected(Member, DeclaringClass),
differentRuntimePackage(CurrentClass, DeclaringClass).

The first three bullets in the old definition of passesProtectedCheck are simply tests for cases in which restrictedProtectedReference is not true. We achieve the same effect below by negating the predicate.

This rule is careful to avoid unnecessary class loading: MemberClassName only needs to be loaded if the name matches that of a superclass of the current class.

The old rule took this a step further by only loading if the name matched and there was a potential protected member in one of the superclasses. This avoids loading a class that happens to share a name with an indirect superclass but is not, in fact, that superclass. But that's a rare corner case, and doesn't seem to justify the added complexity.

A member reference is allowed by a getfield, putfield, or invokevirtual instruction if it is not a restricted protected reference, or if the type of the target reference is assignable to the type of the current class.

allowedInstanceMemberReference(Environment, MemberClassName, MemberName, MemberDescriptor, StackFrame) :-

thisClass(Environment, CurrentClass),
\+ restrictedProtectedReference(CurrentClass, MemberClassName, MemberName, MemberDescriptor).

allowedInstanceMemberReference(Environment, MemberClassName, MemberName, MemberDescriptor, StackFrame) :-

thisClass(Environment, CurrentClass),
restrictedProtectedReference(CurrentClass, MemberClassName, MemberName, MemberDescriptor),
StackFrame = frame(_, [Target | Rest], _),
isAssignable(Target, CurrentClass).

A method reference is a restricted invokespecial reference if the referenced method is not named <init>, the referenced class is a superclass or direct superinterface of the current class, and the method is not declared private.

restrictedInvokespecialReference(CurrentClass, MethodClassName, MethodName, MethodDescriptor) :-

MethodName \= '<init>',
CurrentClass = class(CurrentClassName, CurrentLoader),
superclassChain(CurrentClassName, CurrentLoader, Classes),
classInterfaceNames(CurrentClass, InterfaceNames),
loadedClasses(CurrentLoader, InterfaceNames, Interfaces),
append(Classes, Interfaces, Supers),
member(class(MethodClassName, _), Supers),
loadedClass(MethodClassName, CurrentLoader, ReferencedClass),
member(ReferencedClass, Supers),
resolvedMember(ReferencedClass, MethodName, MethodDescriptor, DeclaringClass, Method),
isNotPrivate(Method).

A method reference is allowed by an invokespecial instruction if it is not a restricted invokespecial reference, or if the type of the target reference is assignable to the type of the current class.

allowedInvokespecialReference(Environment, MethodClassName, MethodName, MethodDescriptor, StackFrame) :-

thisClass(Environment, CurrentClass),
\+ restrictedInvokeSpecialReference(CurrentClass, MethodClassName, MethodName, MethodDescriptor).

allowedInvokespecialReference(Environment, MethodClassName, MethodName, MethodDescriptor, StackFrame) :-

thisClass(Environment, CurrentClass),
restrictedInvokeSpecialReference(CurrentClass, MethodClassName, MethodName, MethodDescriptor),
StackFrame = frame(_, [Target | Rest], _)),
isAssignable(Target, CurrentClass).

4.10.1.9 Type Checking Instructions

...

getfield

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

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

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

...

invokespecial

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

...

invokevirtual

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

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 allowedInstanceMemberReference(Environment, MethodClassName, MethodName, Descriptor, PoppedFrame),
exceptionStackFrame(StackFrame, ExceptionStackFrame).

...

putfield

A putfield instruction with operand CP is type safe iff CP refers to a constant pool entry denoting a field whose declared type is FieldType, declared in a class FieldClass, and one can validly pop types matching FieldType and FieldClass off the incoming operand stack yielding the outgoing type state. A reference to a protected field may require that further restrictions be placed on the type of the target reference operand (4.10.1.8).

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

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

...

5.4.4 Access Control

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

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

This discussion of access control omits a related restriction on the target of a protected field access or method invocation (the target must be of class D or a subtype of D). That requirement is checked as part of the verification process (4.10.1.8); it is not part of link-time access control.

This discussion also omits certain restrictions on the class named by the symbolic reference to R, depending on the access flags of R. These checks are performed immediately after resolution, as specified for getfield, putfield, invokevirtual, and invokespecial.

The restriction on the referenced type of a protected instance member reference makes more sense as an instruction-specific requirement than as part of the definition of accessibility. Moving the check also gives us better congruence between the protected check of invokevirtual and the non-private check of invokespecial.

The change has a subtle, probably tolerable impact: if invokestatic, getstatic, or putstatic references a non-static, protected member declared in a superclass belonging to another package, referenced via a disallowed class, the check on the referenced class is no longer performed and users would see an IncompatibleClassChangeError rather than an IllegalAccessError. Similarly, such a reference to an <init> method by invokespecial will trigger a NoSuchMethodError rather than an IllegalAccessError.

6.5 getfield

Operation

Fetch field from object

Format

getfield indexbyte1 indexbyte2

Forms

getfield = 180 (0xb4)

Operand Stack

..., objectref →
..., value

Description

The objectref, which must be of type reference, is popped from the operand stack. The unsigned indexbyte1 and indexbyte2 are used to construct an index into the run-time constant pool of the current class (2.6), where the value of the index is (indexbyte1 << 8) | indexbyte2. The run-time constant pool item at that index must be a symbolic reference to a field (5.1), which gives the name and descriptor of the field as well as a symbolic reference to the class in which the field is to be found. The referenced field is resolved (5.4.3.2). The value of the referenced field in objectref is fetched and pushed onto the operand stack.

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

These rules are redundant: verification already guarantees them (4.10.1.9).

Linking Exceptions

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

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

Otherwise, if the resolved field is protected and declared in a different run-time package (5.3) than the current class, and the class symbolically referenced by the instruction is neither the current class, nor a superclass of the current class, nor a subclass of the current class, then the getfield instruction throws an IllegalAccessError.

For improved presentation, this was moved from 5.4.4.

Run-time Exception

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

Notes

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

6.5 invokespecial

Operation

Invoke instance method; special handling for superclass, private, and instance initialization method invocations.

Format

invokespecial indexbyte1 indexbyte2

Forms

invokespecial = 183 (0xb7)

Operand Stack

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

Description

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

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

This rule is redundant: a broader check on all non-private methods in superclasses is performed by verification (4.10.1.9).

If all of the following are true, let C be the direct superclass of the current class:

Otherwise, let C be the class or interface named by the symbolic reference.

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

...

Linking Exceptions

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

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

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

Otherwise, if the resolved method is not an instance initialization method and is not private, and the class symbolically referenced by the instruction is neither the current class, nor a superclass of the current class, nor a direct superinterface of the current class, then the invokespecial instruction throws an IllegalAccessError.

This replaces a VerifyError previously specified by 4.9.2. The check must be delayed until after resolution in order to determine whether the referenced method is private.

Run-time Exceptions

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

Otherwise, if the resolved method is a protected method of a superclass of the current class, declared in a different run-time package, and the class of objectref is not the current class or a subclass of the current class, then invokespecial throws an IllegalAccessError.

Otherwise, if the instruction symbolically references an interface method and the class of objectref does not implement the resolved interface, invokespecial throws an IncompatibleClassChangeError.

Otherwise, if the current class is an interface, and the resolved method is not an instance initialization method and is not private, and the class of objectref does not implement the current interface, invokespecial throws an IncompatibleClassChangeError.

This is a possible fix for JDK-8134358. Like invokeinterface, we can't trust assertions in the verifier that the objectref implements an interface, and so check them dynamically for each objectref.

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

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

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

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

Notes

The difference between the invokespecial instruction and the invokevirtual instruction (invokevirtual) is that invokevirtual invokes a method based on the class of the object. The invokespecial instruction is used to invoke instance initialization methods (2.9) as well as private methods and methods of a superclass of the current class.

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

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

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

6.5 invokevirtual

Operation

Invoke instance method; dispatch based on class

Format

invokevirtual indexbyte1 indexbyte2

Forms

invokevirtual = 182 (0xb6)

Operand Stack

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

Description

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

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

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

These rules are redundant: verification already guarantees them (4.10.1.9).

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

...

Linking Exceptions

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

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

Otherwise, if the resolved method is protected and declared in a different run-time package (5.3) than the current class, and the class symbolically referenced by the instruction is neither the current class, nor a superclass of the current class, nor a subclass of the current class, then the invokevirtual instruction throws an IllegalAccessError.

For improved presentation, this was moved from 5.4.4.

Otherwise, if the resolved method is signature polymorphic, then during resolution of the method type derived from the descriptor in the symbolic reference to the method, any of the exceptions pertaining to method type resolution ([5.4.3.5]) can be thrown.

...

6.5 putfield

Operation

Set field in object

Format

putfield indexbyte1 indexbyte2

Forms

putfield = 181 (0xb5)

Operand Stack

..., objectref, value →
...

Description

The unsigned indexbyte1 and indexbyte2 are used to construct an index into the run-time constant pool of the current class (2.6), where the value of the index is (indexbyte1 << 8) | indexbyte2. The run-time constant pool item at that index must be a symbolic reference to a field (5.1), which gives the name and descriptor of the field as well as a symbolic reference to the class in which the field is to be found. The class of objectref must not be an array. If the field is protected, and it is a member of a superclass of the current class, and the field is not declared in the same run-time package (5.3) as the current class, then the class of objectref must be either the current class or a subclass of the current class.

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

These rules are redundant: verification already guarantees most of them (4.10.1.9). The final restriction is restated below.

The value and objectref are popped from the operand stack. The objectref must be of type reference. The value undergoes value set conversion (2.8.3), resulting in value', and the referenced field in objectref is set to value'.

Linking Exceptions

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

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

Otherwise, if the resolved field is protected and declared in a different run-time package (5.3) than the current class, and the class symbolically referenced by the instruction is neither the current class, nor a superclass of the current class, nor a subclass of the current class, then the putfield instruction throws an IllegalAccessError.

For improved presentation, this was moved from 5.4.4.

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

Run-time Exception

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