JDK-8164693 : 6.5: Clarify wrapping of exceptions during invokedynamic
  • Type: Bug
  • Component: specification
  • Sub-Component: vm
  • Affected Version: 8
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • Submitted: 2016-08-23
  • Updated: 2018-08-03
  • Resolved: 2016-09-28
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 9
9Fixed
Related Reports
Relates :  
Relates :  
Relates :  
Description
There are a number of areas in the JVMS where linking (methods, constants, or indy call sites) can result in a BootstrapMethodError that wraps any Throwable. This can cause problems and confusion e.g. when an asynchronous exception such as ThreadDeath occurs when linking.

Such areas include:

1) invokedynamic, which is specified in JVMS8 to wrap all exceptions in a BootstrapMethodError (where JVMS8 elsewhere states that "exception" really means java.lang.Throwable or a subtype). As an example this can easily be induced with string concatenation that uses indy concat. 

2) the linking of signature-polymorphic methods on MethodHandle and VarHandle.

3) the loading of MethodType and MethodHandle constants in the constant pool.

Unfortunately, JVMS8 is logically wrong, because some Throwables must *not* be wrapped in BootstrapMethodError. These include LinkageErrors from "continuing resolution steps", when those steps (for example) are semantically visible to the Java language, e.g., when invokedynamic implements Java member references (Foo::bar, where a failure to resolve bar *must* throw a LinkageError for bar).

The specification for cases 2 and 3 could be fixed merely by adding new cases to JVMS 6.5, or by loosening the wording of JVMS 6.5 to allow things like ThreadDeath to "creep in", or by loosening wording elsewhere about linkage exceptions. However, the specification for invokedynamic (case 1) is in direct conflict with present and future uses of the instruction to implement "virtualized linkage semantics" of present and future language features. The spec needs to be relaxed to wrap only those exceptions (Throwables) which *cannot* be relevant to the link-time semantics of a language feature being implemented by invokedynamic.

The simplest way to carry this out would be to amend JVMS 6.5 (and the HotSpot RI) to pass Error (and *all* its subtypes) without wrapping, if the linkage of invokedynamic throws such a thing. Such an amendment has many desirable properties:

- It ensures that if a LinkageError, ThreadDeath, or any of the JVMS 6.3 "special" VM errors are thrown, the BSME wrapping process will not touch or interfere with them. There are many baroque subtypes of Error but in practice the ones thrown as part of linkage are special enough to the JVM that wrapping them in BSME defeats their purpose. The most "special" Error subtypes are listed in JVMS 6.3, though this list itself cannot be regarded as complete since ThreadDeath should never be wrapped (notwithstanding the legacy behavior of j.l.r.Method.invoke).

- Allowing any Error to propagate outside of a BSM allows the linkage behavior for specific invokedynamic bootstrap methods to include useful new subtypes of Error as outcomes for linking new language features, without interfering with the JVMS. This is appropriate for invokedynamic since it (unlike the other invocation modes) is a virtualized instruction, with little hardwired behavior. When invokedynamic is used to emulate hardwired JVM behavior (e.g., invokevirtual), its bootstrap method can filter exceptions by wrapping Errors mandated-by-the-JVMS-to-be-wrapped-for-that-hardwired-JVM-behavior either in LinkageError, BootstrapMethodError, UnknownError, or some other wrapping chosen by the author of the bootstrap method, based on the requirements for the particular use case.

- Not wrapping Error allows the correct wrapping of java.lang.Exception (even though we don't mention that type in the JVMS), thus preserving the integrity of Java's venerable exception checking framework. That is, the linking of invokedynamic must not throw a "checked exception", nor a subtype of RuntimeException, at link time.
Comments
@David, i would prefer two bugs, JDK-8163553 can focus on explicit calls to sig-poly methods (which i believe is not dependent on spec updates), and another one (that i will create) for indy (the package doc of j.l.invoke needs to be updated, which may require a CCC)
26-08-2016

Can the implementation be fixed as a P2 (using JDK-8163553?) while the spec catches up later?
26-08-2016

Lowering priority to P4 as spec changes are delivered solely on the timetable of the Umbrella JSR for Java SE. A "P2" spec bug can be delivered no more quickly than a "P4" spec bug.
26-08-2016

Per John, JVMS 6.5 invokedynamic, Linking Exceptions, must be amended (and thus clarified with respect to the behavior of the RI) to express that not all exceptions are wrapped with BootstrapMethodError. The proposed text is: "If resolution of the symbolic reference to the call site specifier throws an exception E, the invokedynamic instruction <add>throws E if the type of E is Error or a subclass, else it</add> throws a BootstrapMethodError that wraps E." "Otherwise, during the continuing resolution of the call site specifier, if invocation of the bootstrap method completes abruptly (��2.6.5) because of a throw of exception E, the invokedynamic instruction <add>throws E if the type of E is Error or a subclass, else it</add> throws a BootstrapMethodError that wraps E."
26-08-2016

Raising priority of this one because RI conflicts (and *must* conflict) with the spec.
25-08-2016

I was not sure what the JVM specification stated about exceptions for resolution of sig-poly methods or MethodType/MethodHandle in the constant pool. I had a look, you are right, specification-wise this is just about invokedynamic linking (the other aspects need to be checked implementation-wise regarding wrapping). I will update the description.
24-08-2016

The first area mentioned in the Description (wrapping during indy BSM execution) is easy to locate (see http://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.invokedynamic.linking-110). However, the second and third areas are not; for example, the resolution of a method type in the constant pool does not involve wrapping (see http://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html#jvms-5.4.3.5-110). Please clarify the Description.
24-08-2016

We need stop wrapping non-Exceptions in BSME, and instead allow all non-Exceptions to percolate out of JVM runtime actions that happen behind bytecodes. (That's a capital 'E', meaning java.lang.Exception as opposed to other Throwables.) All Exceptions, including RuntimeExceptions, should be wrapped in BSME for a failing indy bootstrap, but *no* other types of Throwables. Trying to distinguish "really unspecific" Errors from "specific though unchecked" Errors would be a losing game. I know the JVMS seems to play that game by giving special status to some in JVMS 6.3, but the fact that it leaves out ThreadDeath means that list is incomplete. And there is no principle, in *any* spec., that would allow us to deduce that some subtype of java.lang.Error should be *excluded* from the 6.3 list. http://mail.openjdk.java.net/pipermail/hotspot-dev/2016-August/024319.html http://mail.openjdk.java.net/pipermail/hotspot-dev/2016-August/024332.html
24-08-2016