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