JDK-8019184 : MethodHandles.catchException() fails when methods have 8 args + varargs
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.lang.invoke
  • Affected Version: 7u40
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • OS: generic
  • Submitted: 2013-06-26
  • Updated: 2014-10-15
  • Resolved: 2013-07-03
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 7 JDK 8
7u60Fixed 8 b100Fixed
Related Reports
Duplicate :  
Duplicate :  
Description
FULL PRODUCT VERSION :
java version  " 1.7.0_40-ea " 
Java(TM) SE Runtime Environment (build 1.7.0_40-ea-b29)
Java HotSpot(TM) 64-Bit Server VM (build 24.0-b48, mixed mode)


ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 6.1.7600]

EXTRA RELEVANT SYSTEM CONFIGURATION :
64 bit OS and VM.

A DESCRIPTION OF THE PROBLEM :
When binding an exception handler for a method using java.lang.invoke.MethodHandles.catchException()  the binding will fail if the target has eight arguments plus a trailing vararg Object[] argument. Smaller numbers of arguments before the varargs work.

REGRESSION.  Last worked in version 7u25

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Build attached test case. Run it, and observe the output.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
java -classpath . MethodHandleBug
Java Version is 1.7.0_25.

Working case (8 args).

Handler is a MethodHandle(Exception)Object.
Body8 is a MethodHandle(Object,Object,Object,Object,Object,Object,Object,Object[])Object.
Prim8 is a MethodHandle(Object,Object,Object,Object,Object,Object,Object,Object[])Object.
Prim8 with Handler is a MethodHandle(Object,Object,Object,Object,Object,Object,Object,Object[])Object.
Body8 with exception is a MethodHandle(Exception,Object,Object,Object,Object,Object,Object,Object,Object[])Object.
Prim8 with fallback to body8 is a MethodHandle(Object,Object,Object,Object,Object,Object,Object,Object[])Object.

Failing case (9 args).

Handler is a MethodHandle(Exception)Object.
Body9 is a MethodHandle(Object,Object,Object,Object,Object,Object,Object,Object,Object[])Object.
Prim9 is a MethodHandle(Object,Object,Object,Object,Object,Object,Object,Object,Object[])Object.
Prim9 with Handler is a MethodHandle(Object,Object,Object,Object,Object,Object,Object,Object,Object[])Object.
Body9 with exception is a MethodHandle(Exception,Object,Object,Object,Object,Object,Object,Object,Object,Object[])Object.
Prim9 with fallback to body9 is a MethodHandle(Object,Object,Object,Object,Object,Object,Object,Object,Object[])Object.

ACTUAL -
java -classpath . MethodHandleBug
Java Version is 1.7.0_40-ea.

Working case (8 args).

Handler is a MethodHandle(Exception)Object.
Body8 is a MethodHandle(Object,Object,Object,Object,Object,Object,Object,Object[])Object.
Prim8 is a MethodHandle(Object,Object,Object,Object,Object,Object,Object,Object[])Object.
Prim8 with Handler is a MethodHandle(Object,Object,Object,Object,Object,Object,Object,Object[])Object.
Body8 with exception is a MethodHandle(Exception,Object,Object,Object,Object,Object,Object,Object,Object[])Object.
Prim8 with fallback to body8 is a MethodHandle(Object,Object,Object,Object,Object,Object,Object,Object[])Object.

Failing case (9 args).

Handler is a MethodHandle(Exception)Object.
Body9 is a MethodHandle(Object,Object,Object,Object,Object,Object,Object,Object,Object[])Object.
Prim9 is a MethodHandle(Object,Object,Object,Object,Object,Object,Object,Object,Object[])Object.
Prim9 with Handler is a MethodHandle(Object,Object,Object,Object,Object,Object,Object,Object,Object)Object.
Body9 with exception is a MethodHandle(Exception,Object,Object,Object,Object,Object,Object,Object,Object,Object[])Object.
Exception in thread  " main "  java.lang.IllegalArgumentException: target and handler types must match: (Object,Object,Object,Object,Object,Object,Object,Object,Object)Object != (Exception,Object,Object,Object,Object,Object,Object,Object,Object,Object[])Object
at java.lang.invoke.MethodHandleStatics.newIllegalArgumentException(MethodHandleStatics.java:113)
at java.lang.invoke.MethodHandles.misMatchedTypes(MethodHandles.java:2182)
at java.lang.invoke.MethodHandles.catchException(MethodHandles.java:2245)
at MethodHandleBug.main(MethodHandleBug.java:98)


ERROR MESSAGES/STACK TRACES THAT OCCUR :
Exception in thread  " main "  java.lang.IllegalArgumentException: target and handler types must match: (Object,Object,Object,Object,Object,Object,Object,Object,Object)Object != (Exception,Object,Object,Object,Object,Object,Object,Object,Object,Object[])Object
at java.lang.invoke.MethodHandleStatics.newIllegalArgumentException(MethodHandleStatics.java:113)
at java.lang.invoke.MethodHandles.misMatchedTypes(MethodHandles.java:2182)
at java.lang.invoke.MethodHandles.catchException(MethodHandles.java:2245)
at MethodHandleBug.main(MethodHandleBug.java:98)


REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;

public class MethodHandleBug {

    public static MethodHandle handler;
    public static MethodHandle body8;
    public static MethodHandle prim8;
    public static MethodHandle body9;
    public static MethodHandle prim9;
    
    public static Object handler(Exception e) {
        return null;
    }
    
    public static Object body8(
            Object a1, Object a2, Object a3, Object a4,
            Object a5, Object a6, Object a7, Object...a8) {
        return null;
    }
    
    public static Object prim8(
            Object a1, Object a2, Object a3, Object a4,
            Object a5, Object a6, Object a7, Object...a8) {
        return null;
    }
    

    public static Object body9(
            Object a1, Object a2, Object a3, Object a4,
            Object a5, Object a6, Object a7, Object a8, Object...a9) {
        return null;
    }
    
    public static Object prim9(
            Object a1, Object a2, Object a3, Object a4,
            Object a5, Object a6, Object a7, Object a8, Object...a9) {
        return null;
    }
    
    static {
        try {
            handler = MethodHandles.lookup().findStatic(
                    MethodHandleBug.class,  " handler " ,
                    MethodType.methodType(Object.class, Exception.class));
            prim8 = MethodHandles.lookup().findStatic(
                    MethodHandleBug.class,  " prim8 " ,
                    MethodType.methodType(
                            Object.class, Object.class, Object.class, Object.class,
                            Object.class, Object.class, Object.class, Object.class,
                            Object[].class));
            body8 = MethodHandles.lookup().findStatic(
                    MethodHandleBug.class,  " body8 " ,
                    MethodType.methodType(
                            Object.class, Object.class, Object.class, Object.class,
                            Object.class, Object.class, Object.class, Object.class,
                            Object[].class));
            prim9 = MethodHandles.lookup().findStatic(
                    MethodHandleBug.class,  " prim9 " ,
                    MethodType.methodType(
                            Object.class, Object.class, Object.class, Object.class,
                            Object.class, Object.class, Object.class, Object.class,
                            Object.class, Object[].class));
            body9 = MethodHandles.lookup().findStatic(
                    MethodHandleBug.class,  " body9 " ,
                    MethodType.methodType(
                            Object.class, Object.class, Object.class, Object.class,
                            Object.class, Object.class, Object.class, Object.class,
                            Object.class, Object[].class));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        System.out.printf( " Java Version is %s.
 " , System.getProperty( " java.version " ));

        System.out.printf( " 
Working case (8 args).

 " );
        System.out.printf( " Handler is a %s.
Body8 is a %s.
Prim8 is a %s.
 " , handler, body8, prim8);
        MethodHandle primWithHandler8 = MethodHandles.catchException(
                prim8, Exception.class, handler);
        System.out.printf( " Prim8 with Handler is a %s.
 " , primWithHandler8);
        MethodHandle bodyWithEXcp8 = MethodHandles.dropArguments(body8, 0, Exception.class);
        System.out.printf( " Body8 with exception is a %s.
 " , bodyWithEXcp8);
        MethodHandle primFallBackToBody8 = MethodHandles.catchException(
            primWithHandler8, Exception.class, bodyWithEXcp8);
        System.out.printf( " Prim8 with fallback to body8 is a %s.
 " , primFallBackToBody8);
        
        System.out.printf( " 
Failing case (9 args).

 " );
        System.out.printf( " Handler is a %s.
Body9 is a %s.
Prim9 is a %s.
 " , handler, body9, prim9);
        MethodHandle primWithHandler9 = MethodHandles.catchException(
                prim9, Exception.class, handler);
        System.out.printf( " Prim9 with Handler is a %s.
 " , primWithHandler9);
        MethodHandle bodyWithEXcp9 = MethodHandles.dropArguments(
            body9, 0, Exception.class);
        System.out.printf( " Body9 with exception is a %s.
 " , bodyWithEXcp9);
        MethodHandle primFallBackToBody9 = MethodHandles.catchException(
            primWithHandler9, Exception.class, bodyWithEXcp9);
        System.out.printf( " Prim9 with fallback to body9 is a %s.
 " , primFallBackToBody9);
    }
}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
We have changed our source to work round this problem by gathering more args as varargs, but the same problem could crop up in other areas we have not yet tested.
Comments
SQE OK
11-07-2013

still waiting for SQE-OK
10-07-2013

I will remove the nmi since the justification has been added. We will need to wait for SQE-OK before we can approve this request.
09-07-2013

7u40-critical-request Justification: This is a bug in the implementation and must be backported to 7u40.
09-07-2013

I am adding the 'nmi' label. Once the justification and SQE-OK is added - remove the "nmi" label and this issue will re-appear on the list for approvals.
05-07-2013

Need Dev justification and SQE-OK before the release team will review, and then this can be approved.
03-07-2013

The bug seems to be in MethodHandlesImpl.makeGuardWithCatch using ValueConversions.varargsArray: return makeCollectArguments(ginvoker, ValueConversions.varargsArray(nargs), 0, false); ValueConversions.varargsArray returns a MethodHandle which's type is: MethodHandle(Object,Object,Object,Object,Object,Object,Object,Object,Object)Object[] It doesn't preserve the trailing Object[].
02-07-2013

Suggested fix: diff --git a/src/share/classes/java/lang/invoke/MethodHandleImpl.java b/src/share/classes/java/lang/invoke/MethodHandleImpl.java --- a/src/share/classes/java/lang/invoke/MethodHandleImpl.java +++ b/src/share/classes/java/lang/invoke/MethodHandleImpl.java @@ -747,7 +747,8 @@ GuardWithCatch gguard = new GuardWithCatch(gtarget, exType, gcatcher); if (gtarget == null || gcatcher == null) throw new InternalError(); MethodHandle ginvoker = GuardWithCatch.VARARGS_INVOKE.bindReceiver(gguard); - return makeCollectArguments(ginvoker, ValueConversions.varargsArray(nargs), 0, false); + MethodHandle gcollect = makeCollectArguments(ginvoker, ValueConversions.varargsArray(nargs), 0, false); + return makePairwiseConvert(gcollect, type, 2); } }
02-07-2013

The problem is when doing a MethodHandles.catchException on Prim9 the last argument type is changed from Object[] to Object: Body9 is a MethodHandle(Object,Object,Object,Object,Object,Object,Object,Object,Object[])Object. Prim9 is a MethodHandle(Object,Object,Object,Object,Object,Object,Object,Object,Object[])Object. Prim9 with Handler is a MethodHandle(Object,Object,Object,Object,Object,Object,Object,Object,Object)Object. Body9 with exception is a MethodHandle(Exception,Object,Object,Object,Object,Object,Object,Object,Object,Object[])Object.
02-07-2013