Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8268336

Upstream: 8267989: Exceptions thrown during upcalls should be handled (Pt. 1)

XMLWordPrintable

    • Icon: CSR CSR
    • Resolution: Withdrawn
    • Icon: P3 P3
    • None
    • tools
    • None
    • behavioral
    • minimal
    • Hide
      This is a change in behavior of an API that is currently incubating. Since the fix makes the implementation more lenient, it is not possible for arguments that were previously accepted to be rejected. Existing call sites that use VarHandle access methods could now report an IllegalStateException when used in combination with exactly those VarHandles that the more lenient check allows.
      Show
      This is a change in behavior of an API that is currently incubating. Since the fix makes the implementation more lenient, it is not possible for arguments that were previously accepted to be rejected. Existing call sites that use VarHandle access methods could now report an IllegalStateException when used in combination with exactly those VarHandles that the more lenient check allows.
    • Java API

      Summary

      Be more lenient when checking for checked exception thrown by MethodHandles used as arguments to VarHandle combinators.

      Problem

      Currently, the VarHandle combinators found in jdk.incubator.foreign.MemoryHandles try to eagerly check if the method handles that they are given throw any checked exceptions, and if so, reject such method handles. This is done to avoid throwing checked exceptions from any of the access methods on the resulting VarHandle, which do not report any checked exception in their signature or documentation.

      However, this check is too strict, as it can also reject method handles that do not throw any exceptions themselves, but merely depend on another method handle that can throw an exception, which would then be caught and handled by the enclosing method handle.

      Solution

      The solution to this problem is to relax the check for checked exceptions, to be more lenient towards method handles for which it can not be determined eagerly with certainty whether they throw any checked exceptions.

      As a result of this alone, it would again be possible for a VarHandle access method to throw a checked exception not reported in the signature or the documentation. So, to remedy that, the method handles for which it can not be determined eagerly whether they throw a checked exception are wrapped in another method handle (using the catchException combinator), which catches any exceptions thrown by the target method handle, and in the case that they are checked exceptions, throws an IllegalStateException instead, with the original checked exception as a cause. Unchecked exceptions are simply rethrown.

      Specification

      --- a/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/MemoryHandles.java
      +++ b/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/MemoryHandles.java
      @@ -329,6 +329,9 @@ public static VarHandle asUnsigned(VarHandle target, final Class<?> adaptedType)
            * the resulting var handle will have type {@code S} and will feature the additional coordinates {@code A...} (which
            * will be appended to the coordinates of the target var handle).
            * <p>
      +     * If the boxing and unboxing filters throw any checked exceptions when invoked, the resulting var handle will
      +     * throw an {@link IllegalStateException}.
      +     * <p>
            * The resulting var handle will feature the same access modes (see {@link java.lang.invoke.VarHandle.AccessMode} and
            * atomic access guarantees as those featured by the target var handle.
            *
      @@ -338,7 +341,7 @@ public static VarHandle asUnsigned(VarHandle target, final Class<?> adaptedType)
            * @return an adapter var handle which accepts a new type, performing the provided boxing/unboxing conversions.
            * @throws IllegalArgumentException if {@code filterFromTarget} and {@code filterToTarget} are not well-formed, that is, they have types
            * other than {@code (A... , S) -> T} and {@code (A... , T) -> S}, respectively, where {@code T} is the type of the target var handle,
      -     * or if either {@code filterFromTarget} or {@code filterToTarget} throws any checked exceptions.
      +     * or if it's determined that either {@code filterFromTarget} or {@code filterToTarget} throws any checked exceptions.
            */
           public static VarHandle filterValue(VarHandle target, MethodHandle filterToTarget, MethodHandle filterFromTarget) {
               return JLI.filterValue(target, filterToTarget, filterFromTarget);
      @@ -356,6 +359,9 @@ public static VarHandle filterValue(VarHandle target, MethodHandle filterToTarge
            * For the coordinate filters to be well formed, their types must be of the form {@code S1 -> T1, S2 -> T1 ... Sn -> Tn},
            * where {@code T1, T2 ... Tn} are the coordinate types starting at position {@code pos} of the target var handle.
            * <p>
      +     * If any of the filters throws a checked exception when invoked, the resulting var handle will
      +     * throw an {@link IllegalStateException}.
      +     * <p>
            * The resulting var handle will feature the same access modes (see {@link java.lang.invoke.VarHandle.AccessMode}) and
            * atomic access guarantees as those featured by the target var handle.
            *
      @@ -368,7 +374,7 @@ public static VarHandle filterValue(VarHandle target, MethodHandle filterToTarge
            * other than {@code S1 -> T1, S2 -> T2, ... Sn -> Tn} where {@code T1, T2 ... Tn} are the coordinate types starting
            * at position {@code pos} of the target var handle, if {@code pos} is not between 0 and the target var handle coordinate arity, inclusive,
            * or if more filters are provided than the actual number of coordinate types available starting at {@code pos},
      -     * or if any of the filters throws any checked exceptions.
      +     * or if it's determined that any of the filters throws any checked exceptions.
            */
           public static VarHandle filterCoordinates(VarHandle target, int pos, MethodHandle... filters) {
               return JLI.filterCoordinates(target, pos, filters);
      @@ -464,6 +470,9 @@ public static VarHandle permuteCoordinates(VarHandle target, List<Class<?>> newC
            * coordinate type of the target var handle at position {@code pos}, and that target var handle
            * coordinate is supplied by the return value of the filter.
            * <p>
      +     * If any of the filters throws a checked exception when invoked, the resulting var handle will
      +     * throw an {@link IllegalStateException}.
      +     * <p>
            * The resulting var handle will feature the same access modes (see {@link java.lang.invoke.VarHandle.AccessMode}) and
            * atomic access guarantees as those featured by the target var handle.
            *
      @@ -476,7 +485,7 @@ public static VarHandle permuteCoordinates(VarHandle target, List<Class<?>> newC
            * is void, or it is not the same as the {@code pos} coordinate of the target var handle,
            * if {@code pos} is not between 0 and the target var handle coordinate arity, inclusive,
            * if the resulting var handle's type would have <a href="MethodHandle.html#maxarity">too many coordinates</a>,
      -     * or if {@code filter} throws any checked exceptions.
      +     * or if it's determined that {@code filter} throws any checked exceptions.
            */
           public static VarHandle collectCoordinates(VarHandle target, int pos, MethodHandle filter) {
               return JLI.collectCoordinates(target, pos, filter);

            jvernee Jorn Vernee
            jvernee Jorn Vernee
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: