Exceptions thrown when linking sig-poly methods and indy

Paul Sandoz paul.sandoz at oracle.com
Mon Aug 22 22:22:13 UTC 2016


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 hotspot-dev mailing list