United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
JDK-8019184 : MethodHandles.catchException() fails when methods have 8 args + varargs

Details
Type:
Bug
Submit Date:
2013-06-26
Status:
Closed
Updated Date:
2014-09-04
Project Name:
JDK
Resolved Date:
2013-07-03
Component:
core-libs
OS:
generic
Sub-Component:
java.lang.invoke
CPU:
Priority:
P2
Resolution:
Fixed
Affected Versions:
7u40
Fixed Versions:

Related Reports
Backport:
Backport:
Backport:
Backport:
Duplicate:
Duplicate:

Sub Tasks

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

                                     
2013-07-02
URL:   http://hg.openjdk.java.net/jdk8/tl/jdk/rev/bd6949f9dbb2
User:  twisti
Date:  2013-07-03 18:35:51 +0000

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

                                     
2013-07-03
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.
                                     
2013-07-05
7u40-critical-request Justification: This is a bug in the implementation and must be backported to 7u40.
                                     
2013-07-09
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.
                                     
2013-07-09
still waiting for SQE-OK
                                     
2013-07-10
SQE OK
                                     
2013-07-11
URL:   http://hg.openjdk.java.net/jdk8/jdk8/jdk/rev/bd6949f9dbb2
User:  lana
Date:  2013-07-23 18:11:27 +0000

                                     
2013-07-23
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. 

                                     
2013-07-02
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[].
                                     
2013-07-02



Hardware and Software, Engineered to Work Together