Exceptions thrown when linking sig-poly methods and indy

Uwe Schindler uschindler at apache.org
Mon Aug 22 23:12:54 UTC 2016


Hi,

from my understanding of the spec:

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

I think the spec says "exception" not "throwable", so only "Exception" subclasses should be wrapped. Errors should just be rethrown or not catched at all.

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

Why only have special cases for such types? To me "Error" in general should never-ever be wrapped!

Uwe

> 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/MethodHa
> ndleNatives.java:250)
> > 	at
> java.lang.invoke.MethodHandleNatives.linkCallSite(java.base/MethodHandle
> Natives.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/MethodH
> andleStatics.java:108)
> > 	at
> java.lang.invoke.LambdaForm.compileToBytecode(java.base/LambdaForm.ja
> va:816)
> > 	at
> java.lang.invoke.DirectMethodHandle.makePreparedLambdaForm(java.base
> /DirectMethodHandle.java:249)
> > 	at
> java.lang.invoke.DirectMethodHandle.preparedLambdaForm(java.base/Dire
> ctMethodHandle.java:186)
> > 	at
> java.lang.invoke.DirectMethodHandle.preparedLambdaForm(java.base/Dire
> ctMethodHandle.java:175)
> > 	at
> java.lang.invoke.DirectMethodHandle.make(java.base/DirectMethodHandle.
> java:88)
> > 	at
> java.lang.invoke.MethodHandles$Lookup.getDirectMethodCommon(java.bas
> e/MethodHandles.java:2035)
> > 	at
> java.lang.invoke.MethodHandles$Lookup.getDirectMethodNoSecurityManag
> er(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.b
> ase/MethodHandles.java:2172)
> > 	at
> java.lang.invoke.MethodHandleNatives.linkMethodHandleConstant(java.bas
> e/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