Hi,
Recent discussion on the wrapping of exceptions (any Throwable) in LinkageError
be it for invokedynamic and BootstrapMethodError (a spec issue) or for
signature polymorphic linkage (an implementation detail AFAICT) resulted in a
more detailed look at the exception handling in the j.l.invoke code.
To partially fix signature polymorphic linkage i have made some small
modifications [1] but i found i need to dig deeper as there are many other
cases where Throwable is wrapped, specifically with the calls to
MethodHandleStatic.newInternalError:
/*non-public*/ static InternalError newInternalError(Throwable cause) {
return new InternalError(cause);
}
There is also MethodHandleStatic.uncaughtException
/** Propagate unchecked exceptions and errors, but wrap anything checked and
throw that instead. */
/*non-public*/ static Error uncaughtException(Throwable ex) {
if (ex instanceof Error) throw (Error) ex;
if (ex instanceof RuntimeException) throw (RuntimeException) ex;
throw newInternalError("uncaught exception", ex);
}
There may be cases where these are interchangeable, it’s subtle, and i would be
away of replacing calls to newInternalError with uncaughtException.
I propose the following:
1) change newInternalError(String message, Throwable cause) to
newInternalError(String message, Exception cause)
We want to be clear that the cause is an Exception, since this method will
always return InternalError with a message.
2) replace newInternalError(Throwable cause) with
errorOrNewInternalError(Throwable ex)
/*non-public*/ static Error errorOrNewInternalError(Throwable ex) {
if (ex instanceof Error) return (Error) ex;
return newInternalError("uncaught exception", ex);
}
In all cases existing Errors will never be wrapped.
3) It’s tempting to rename uncaughtException with uncheckedOrNewInternalError.
Paul.
[1]
diff -r 248159c6e61a
src/java.base/share/classes/java/lang/invoke/LambdaForm.java
--- a/src/java.base/share/classes/java/lang/invoke/LambdaForm.java Wed Aug
24 11:23:58 2016 -0700
+++ b/src/java.base/share/classes/java/lang/invoke/LambdaForm.java Wed Aug
24 15:31:29 2016 -0700
@@ -41,7 +41,6 @@
import static java.lang.invoke.LambdaForm.BasicType.*;
import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeStatic;
import static java.lang.invoke.MethodHandleStatics.*;
-import java.util.Objects;
/**
* The symbolic, non-executable form of a method handle's invocation semantics.
@@ -856,7 +855,7 @@
System.out.println("LambdaForm compilation failed: " + this);
bge.printStackTrace(System.out);
}
- } catch (Error | Exception e) {
+ } catch (Exception e) {
throw newInternalError(this.toString(), e);
}
}
diff -r 248159c6e61a
src/java.base/share/classes/java/lang/invoke/MethodHandle.java
--- a/src/java.base/share/classes/java/lang/invoke/MethodHandle.java Wed Aug
24 11:23:58 2016 -0700
+++ b/src/java.base/share/classes/java/lang/invoke/MethodHandle.java Wed Aug
24 15:31:29 2016 -0700
@@ -957,7 +957,7 @@
if (!fail) return needType;
// elicit an error:
this.asType(needType);
- throw newInternalError("should not return", null);
+ throw newInternalError("should not return");
}
private void spreadArrayChecks(Class<?> arrayType, int arrayLength) {
diff -r 248159c6e61a
src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java
--- a/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java
Wed Aug 24 11:23:58 2016 -0700
+++ b/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java
Wed Aug 24 15:31:29 2016 -0700
@@ -380,8 +380,11 @@
}
}
} catch (Throwable ex) {
- if (ex instanceof LinkageError)
- throw (LinkageError) ex;
+ // Pass through all instances of Error, thus ensuring errors such
as
+ // ThreadDeath, StackOverflowException, OutOfMemoryException etc.
+ // are not wrapped
+ if (ex instanceof Error)
+ throw (Error) ex;
else
throw new LinkageError(ex.getMessage(), ex);