Exceptions thrown when linking sig-poly methods and indy

David Holmes david.holmes at oracle.com
Mon Aug 22 22:58:50 UTC 2016


Hi Paul,

As per my comments in the bug report I think the specification parts 
that state to wrap all "exceptions" are too strict (for want of a better 
word). One view is that they should only consider synchronous exceptions 
directly triggered by a problem with resolution. Another possibility is 
that "exception" was not intended to mean "any exception instance being 
a subclass of Throwable", but rather was intended to be Exception - and 
hence all subclasses of Error would be excluded.

Or the spec is mostly right and (other than truly async exceptions like 
ThreadDeath) any exception encountered due to the linking should be wrapped.

There are other places in the VM and libraries where exception wrapping 
occurs but I'm not sure if we have special handling for specific kinds 
of exceptions (Exceptions thrown during static initialization; 
Exceptions thrown during class loading/linking/resolution; exceptions 
thrown when a task is submitted to an Executor; etc).

Cheers,
David

On 23/08/2016 8:22 AM, Paul Sandoz wrote:
> Hi,
>
> For methods that make an appeal to Java code such as an up call from HotSpot to Java for linking signature-polymorphic methods or linking indy call sites (invoking bootstrap methods) it’s possible that certain important exceptions get wrapped in a LinkageError or a BootstrapMethodError. Such important exceptions are ThreadDeath, StackOverflow and possibly OOME.
>
> Some j.u.concurrent classes were updated to use VarHandles and this now very occasionally results in a test failure where ThreadDeath is wrapped in LinkageError and thus thread-based JDK code reacts differently.
>
> See https://bugs.openjdk.java.net/browse/JDK-8163553.
>
> It’s easier to reproduce by updating the failing test with an indy [1], which fails with various errors such as:
>
> Exception in thread "Thread-0" java.lang.BootstrapMethodError: call site initialization exception
> 	at java.lang.invoke.CallSite.makeSite(java.base/CallSite.java:347)
> 	at java.lang.invoke.MethodHandleNatives.linkCallSiteImpl(java.base/MethodHandleNatives.java:250)
> 	at java.lang.invoke.MethodHandleNatives.linkCallSite(java.base/MethodHandleNatives.java:240)
> 	at Stop.lambda$test$1(Stop.java:15)
> 	at java.lang.Thread.run(java.base/Thread.java:843)
> Caused by: java.lang.ThreadDeath
> 	at java.lang.Thread.stop(java.base/Thread.java:948)
> 	at java.lang.ThreadGroup.stopOrSuspend(java.base/ThreadGroup.java:698)
> 	at java.lang.ThreadGroup.stop(java.base/ThreadGroup.java:610)
> 	at Stop.lambda$test$2(Stop.java:32)
> 	... 1 more
>
> or more obscurely (and erroneously):
>
> Exception in thread "Thread-0" java.lang.InternalError: DMH.invokeStatic__V=Lambda(a0:L)=>{
>     t1:L=DirectMethodHandle.internalMemberName(a0:L);
>     t2:V=MethodHandle.linkToStatic(t1:L);void}
> 	at java.lang.invoke.MethodHandleStatics.newInternalError(java.base/MethodHandleStatics.java:108)
> 	at java.lang.invoke.LambdaForm.compileToBytecode(java.base/LambdaForm.java:816)
> 	at java.lang.invoke.DirectMethodHandle.makePreparedLambdaForm(java.base/DirectMethodHandle.java:249)
> 	at java.lang.invoke.DirectMethodHandle.preparedLambdaForm(java.base/DirectMethodHandle.java:186)
> 	at java.lang.invoke.DirectMethodHandle.preparedLambdaForm(java.base/DirectMethodHandle.java:175)
> 	at java.lang.invoke.DirectMethodHandle.make(java.base/DirectMethodHandle.java:88)
> 	at java.lang.invoke.MethodHandles$Lookup.getDirectMethodCommon(java.base/MethodHandles.java:2035)
> 	at java.lang.invoke.MethodHandles$Lookup.getDirectMethodNoSecurityManager(java.base/MethodHandles.java:1992)
> 	at java.lang.invoke.MethodHandles$Lookup.getDirectMethodForConstant(java.base/MethodHandles.java:2223)
> 	at java.lang.invoke.MethodHandles$Lookup.linkMethodHandleConstant(java.base/MethodHandles.java:2172)
> 	at java.lang.invoke.MethodHandleNatives.linkMethodHandleConstant(java.base/MethodHandleNatives.java:499)
> 	at Stop.lambda$test$1(Stop.java:15)
> 	at java.lang.Thread.run(java.base/Thread.java:843)
> Caused by: java.lang.ThreadDeath
> 	at java.lang.Thread.stop(java.base/Thread.java:948)
> 	at java.lang.ThreadGroup.stopOrSuspend(java.base/ThreadGroup.java:698)
> 	at java.lang.ThreadGroup.stop(java.base/ThreadGroup.java:610)
> 	at Stop.lambda$test$2(Stop.java:32)
> 	... 1 more
>
>
> 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
>
>
> 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.
>
> 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)?
>
> Should such exceptions be wrapped or thrown directly? if the latter that would require a specification update for invokedynamic.
>
> If they are wrapped should the VM check the cause, unwrap for special cases, and rethrow the cause?
>
> Paul.
>
> [1]
> import java.util.concurrent.CountDownLatch;
>
> public class Stop {
>
>     public static void main(String[] args) throws Exception {
>         test();
>     }
>
>     public static void test() throws Exception {
>         final CountDownLatch ready = new CountDownLatch(1);
>         final ThreadGroup group = new ThreadGroup("");
>
>         final Thread second = new Thread(group, () -> {
>             ready.countDown();
>             final Runnable r = () -> { System.out.println("RUN"); };
>             r.run();
>             while (true) {
>                 try {
>                     Thread.sleep(60000);
>                 } catch (InterruptedException shouldNotHappen) {
>                 }
>             }
>         });
>
>         final Thread first = new Thread(group, () -> {
>             // Wait until "second" is started
>             try {
>                 ready.await();
>             } catch (InterruptedException shouldNotHappen) {
>             }
>             // Now stop the group
>             group.stop();
>         });
>
>         // Launch two threads as part of the same thread group
>         first.start();
>         second.start();
>
>         // Check that the second thread is terminated when the
>         // first thread terminates the thread group.
>         second.join();
>         // Test passed - if never get here the test times out and fails.
>     }
> }
>


More information about the jdk9-dev mailing list