Details
-
Bug
-
Resolution: Unresolved
-
P4
-
23
Description
During linking, various "resolution activities" require the loading of classes. Primarily, this is triggered by constant resolution, which specifically calls out the loading of certain named classes. (And, aside from CONSTANT_Dynamic and CONSTANT_InvokeDynamic, the timing of resolution is extremely flexible.) Most of the 5.4 discussion about the timing of linking and, recursively, class loading, seems focused on resolution.
But there are other circumstances in which a class is loaded without a corresponding constant resolution. These other circumstances are sometimes poorly-specified or unspecified. This is of some concern, because class loading attempts are observable to user-defined class loaders, and because class loading failures may (or may not) manifest as user-observable exceptions.
Cases of class loading without resolution that we've identified include:
- The recursive loading of superclasses and superinterfaces during class loading (5.3.5). Unlike most other cases, this is mandated to occur at a specific time, and error case behavior is well-specified.
- Subtype checks during verification. This is somewhat specified with the 'loadedClass' verifier rule, but that's buried in the guts of various verification rules, can sometimes be implementation-dependent (depending on which predicate the implementation chooses to test first), and doesn't address verification by type inference (4.10.2). There's an imprecise mention in 5.4.1 ("Verification may cause additional class and interfaces to be loaded"). One reading of this rule is that verification can load any class it wishes; another reading is that verification can load some classes, but these will be justified by the specification.
- JIT-specific loading of classes in a descriptor (JDK-8334324). There's no specific action in JVMS that this corresponds to, it's just an implementation looking for more information about the parameters to a method. This action may not even correspond to "linking", depending on how we define the term.
- Checking whether an exception should be handled. Per 2.10, implementations must check whether "the exception type is the same class as or a subclass of the class of exception that the exception handler handles". An exception handler "handles" a class by naming it with a CONSTANT_Class. It is not stated that this constant must be *resolved* in order to perform this check, or simply *loaded*. HotSpot performs resolution and throws any resolution error (including, potentially, an IllegalAccessError). Another implementation, J9, simply loads the class without resolution.
- Reflection of attributes. Metadata stored in most attributes, like annotations, is never directly interpreted by the abstract JVM, but user-driven reflection activities may force such attributes to be interpreted and corresponding classes to be loaded. Might we allow an implementation to eagerly load classes mentioned by RuntimeVisibleAnnotations? I'm not sure this has come up in practice, but I'm also not sure the spec provides a definitive answer if it did.
- Various classes are loaded before we get to the "initial class" specified in 5.2, including some core JDK classes and, potentially, a user-defined class loader. 5.2 doesn't have anything to say directly about which classes are loaded before the initial class.
- In the future with value classes (JDK-8317278), the 'LoadableDescriptors' attribute lists field descriptors that the JVM implementation can optionally load, without any corresponding resolution action. The draft JVMS explicitly allows for loading in this case, and specifies that any errors must be ignored. The timing of this loading is specified to occur "during any phase of linking", although that's a bit vague. (Does it allow for loading at JIT compilation time?)
- In the future under Leyden, the set of classes loaded (and even initialized) before 'main' may be user-configurable.
There are probably other cases. HotSpot seems to somewhat freely load classes when it finds doing so to be useful.
We need a consensus on the precise circumstances that justify loading additional classes. This could be very narrow—you can only load classes when the spec permits it—or very permissive—implementations can load any classes, whenever they want. We also need to clarify any appropriate error handling behavior when such loading occurs. Then we need spec language (probably in 5.4?) that captures these rules.
But there are other circumstances in which a class is loaded without a corresponding constant resolution. These other circumstances are sometimes poorly-specified or unspecified. This is of some concern, because class loading attempts are observable to user-defined class loaders, and because class loading failures may (or may not) manifest as user-observable exceptions.
Cases of class loading without resolution that we've identified include:
- The recursive loading of superclasses and superinterfaces during class loading (5.3.5). Unlike most other cases, this is mandated to occur at a specific time, and error case behavior is well-specified.
- Subtype checks during verification. This is somewhat specified with the 'loadedClass' verifier rule, but that's buried in the guts of various verification rules, can sometimes be implementation-dependent (depending on which predicate the implementation chooses to test first), and doesn't address verification by type inference (4.10.2). There's an imprecise mention in 5.4.1 ("Verification may cause additional class and interfaces to be loaded"). One reading of this rule is that verification can load any class it wishes; another reading is that verification can load some classes, but these will be justified by the specification.
- JIT-specific loading of classes in a descriptor (JDK-8334324). There's no specific action in JVMS that this corresponds to, it's just an implementation looking for more information about the parameters to a method. This action may not even correspond to "linking", depending on how we define the term.
- Checking whether an exception should be handled. Per 2.10, implementations must check whether "the exception type is the same class as or a subclass of the class of exception that the exception handler handles". An exception handler "handles" a class by naming it with a CONSTANT_Class. It is not stated that this constant must be *resolved* in order to perform this check, or simply *loaded*. HotSpot performs resolution and throws any resolution error (including, potentially, an IllegalAccessError). Another implementation, J9, simply loads the class without resolution.
- Reflection of attributes. Metadata stored in most attributes, like annotations, is never directly interpreted by the abstract JVM, but user-driven reflection activities may force such attributes to be interpreted and corresponding classes to be loaded. Might we allow an implementation to eagerly load classes mentioned by RuntimeVisibleAnnotations? I'm not sure this has come up in practice, but I'm also not sure the spec provides a definitive answer if it did.
- Various classes are loaded before we get to the "initial class" specified in 5.2, including some core JDK classes and, potentially, a user-defined class loader. 5.2 doesn't have anything to say directly about which classes are loaded before the initial class.
- In the future with value classes (JDK-8317278), the 'LoadableDescriptors' attribute lists field descriptors that the JVM implementation can optionally load, without any corresponding resolution action. The draft JVMS explicitly allows for loading in this case, and specifies that any errors must be ignored. The timing of this loading is specified to occur "during any phase of linking", although that's a bit vague. (Does it allow for loading at JIT compilation time?)
- In the future under Leyden, the set of classes loaded (and even initialized) before 'main' may be user-configurable.
There are probably other cases. HotSpot seems to somewhat freely load classes when it finds doing so to be useful.
We need a consensus on the precise circumstances that justify loading additional classes. This could be very narrow—you can only load classes when the spec permits it—or very permissive—implementations can load any classes, whenever they want. We also need to clarify any appropriate error handling behavior when such loading occurs. Then we need spec language (probably in 5.4?) that captures these rules.
Attachments
Issue Links
- relates to
-
JDK-8317278 JVM implementation of value classes and objects
- In Progress
-
JDK-8334324 Method::load_signature_classes initiates spontaneous class loading
- Open