Exceptions thrown when linking sig-poly methods and indy

John Rose john.r.rose at oracle.com
Mon Aug 22 23:19:11 UTC 2016

On Aug 22, 2016, at 3:22 PM, Paul Sandoz <paul.sandoz at oracle.com> wrote:

> The invokedynamic specification states that a linking exception be wrapped in BootstrapMethodError (a subtype of LinkageError):
>  https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.invokedynamic <https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.invokedynamic>

Thanks for bringing this up.

It is a known weak spot in JSR 292.  If the resolution of a CP constant being fed into a BSM causes a linkage error (LE) there is no compelling reason to re-wrap it in a BSM, other than the over-simplified language of the spec.

IIRC this language messes up exception structure from JDK 8 lambda capture, since that uses indy.

> I think we need to review how we manage certain special Error types thrown from linking, be the thrown directly or extracted from a known wrapping exception and re-thrown.

I would support wrapping fewer low-level conditions in BSME, especially those "around" and not "inside" the actual BSM call.  (Where the BSM itself can help define what "around" means, as part of argument validation.)  Especially LE's.  Also Errors like TD/SOE/OOME/IE/VME that are logically "out of band" relative to the execution of the current bytecode.

In retrospect, it would have been better to specify that any java.lang.Error arising from the linkage (including bootstrap) of an indy is just passed up directly through the bytecode that is suffering the linkage failure.  Let the BSM itself catch and BSME-wrap such things, if it is important not to let them escape unwrapped.  The main reason for BSME is to convert java.lang.Exceptions (even RTE's) to LinkageErrors, since BSM execution *is* linkage, and normal Exceptions cannot be allowed to leak.

An older analogous case is core reflection, which throws InvocationTargetException to avoid allowing normal Exceptions to leak.  Unlike BSME it is a checked exception, but otherwise similar questions arise about wrapping vs. passing.

> Certainly there are cases when linking an indy call set where BootstrapMethodError should be thrown but is not (see above), but in general how should we treat the occurrence of a ThreadDeath, StackOverflow or OOME (or VirtualMachineError)?

InternalError is one of those evil conditions that can occur out of band, and doesn't get wrapped.  In the case you cite, the JSR 292 linkage logic is choking on a another such evil condition (TD) and throw up an IE.  Throwing the right evil error is a QOI issue, rather than a spec. conformance issue.  Any InternalError is a mark of bad QOI, rather than some correctly implemented spec.

> Should such exceptions be wrapped or thrown directly? if the latter that would require a specification update for invokedynamic.

We need a specification update.

> If they are wrapped should the VM check the cause, unwrap for special cases, and rethrow the cause?

We do too much of that already.  Stuff like this:

            if (ex instanceof LinkageError)
                throw (LinkageError) ex;
                throw new LinkageError(ex.getMessage(), ex);

            if (ex instanceof BootstrapMethodError)
                bex = (BootstrapMethodError) ex;
                bex = new BootstrapMethodError("call site initialization exception", ex);

The instanceof checks should be simply java.lang.Error, I think.  That's the best classification we have,
and it's not worth making a list of out-of-band Errors and in-band Errors.  If you look at the set of
subtypes you'll see many strange things (AWTError anyone?), but in the end all of them, being
unchecked, are effectively throwable from anywhere.  And like I said, more careful filtering can
be done by the BSM itself.  As a special note, if a BSM throws a *checked* exception, it will *always*
be wrapped in a BSME.  This is why (IIUC) the LambdaConversionException is checked:  It is
a specially distinguished internal error inside the lambda capture runtime, which will usually be
found wrapped in a BSME.

— John

More information about the jdk9-dev mailing list