j.l.invoke and the wrapping of exceptions

Paul Sandoz paul.sandoz at oracle.com
Wed Aug 24 23:01:56 UTC 2016


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);


More information about the core-libs-dev mailing list