8036117: MethodHandles.catchException doesn't handle VarargsCollector right (8034120 failed)
authorvlivanov
Tue, 11 Mar 2014 19:54:33 +0400
changeset 23338 0a84d339822a
parent 23337 d4a11c730d92
child 23339 d66b18f52418
child 23636 e8579a943a6f
8036117: MethodHandles.catchException doesn't handle VarargsCollector right (8034120 failed) Reviewed-by: jrose, twisti
jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java
jdk/test/java/lang/invoke/MethodHandles/TestCatchException.java
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java	Tue Mar 11 14:18:46 2014 +0100
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java	Tue Mar 11 19:54:33 2014 +0400
@@ -736,16 +736,17 @@
     @LambdaForm.Hidden
     static Object guardWithCatch(MethodHandle target, Class<? extends Throwable> exType, MethodHandle catcher,
                                  Object... av) throws Throwable {
+        // Use asFixedArity() to avoid unnecessary boxing of last argument for VarargsCollector case.
         try {
-            return target.invokeWithArguments(av);
+            return target.asFixedArity().invokeWithArguments(av);
         } catch (Throwable t) {
             if (!exType.isInstance(t)) throw t;
-            Object[] args = prepend(t, av);
-            return catcher.invokeWithArguments(args);
+            return catcher.asFixedArity().invokeWithArguments(prepend(t, av));
         }
     }
 
     /** Prepend an element {@code elem} to an {@code array}. */
+    @LambdaForm.Hidden
     private static Object[] prepend(Object elem, Object[] array) {
         Object[] newArray = new Object[array.length+1];
         newArray[0] = elem;
--- a/jdk/test/java/lang/invoke/MethodHandles/TestCatchException.java	Tue Mar 11 14:18:46 2014 +0100
+++ b/jdk/test/java/lang/invoke/MethodHandles/TestCatchException.java	Tue Mar 11 19:54:33 2014 +0400
@@ -72,19 +72,55 @@
         assertEquals(x, 17);
     }
 
+    final static Object masterParam = new Object();
+    final static Object[] masterTail = new Object[] { "str" };
+    static Exception masterEx = new Exception();
 
     public static Object m1(Object o1, Object o2, Object o3, Object o4, Object o5,
                             Object o6, Object o7, Object o8, Object... tail) {
+        assertEquals(masterParam, o1);
+        assertEquals(masterParam, o2);
+        assertEquals(masterParam, o3);
+        assertEquals(masterParam, o4);
+        assertEquals(masterParam, o5);
+        assertEquals(masterParam, o6);
+        assertEquals(masterParam, o7);
+        assertEquals(masterParam, o8);
+        assertEquals(masterTail, tail);
         return tail;
     }
 
     public static Object m2(Exception e, Object o1, Object o2, Object o3, Object o4,
                             Object o5, Object o6, Object o7, Object o8, Object... tail) {
+        assertEquals(masterEx, e);
+        assertEquals(masterParam, o1);
+        assertEquals(masterParam, o2);
+        assertEquals(masterParam, o3);
+        assertEquals(masterParam, o4);
+        assertEquals(masterParam, o5);
+        assertEquals(masterParam, o6);
+        assertEquals(masterParam, o7);
+        assertEquals(masterParam, o8);
+        assertEquals(masterTail, tail);
         return tail;
     }
 
+    public static Object throwEx(Object o1, Object o2, Object o3, Object o4, Object o5,
+                                 Object o6, Object o7, Object o8, Object... tail) throws Exception {
+        assertEquals(masterParam, o1);
+        assertEquals(masterParam, o2);
+        assertEquals(masterParam, o3);
+        assertEquals(masterParam, o4);
+        assertEquals(masterParam, o5);
+        assertEquals(masterParam, o6);
+        assertEquals(masterParam, o7);
+        assertEquals(masterParam, o8);
+        assertEquals(masterTail, tail);
+        throw masterEx;
+    }
+
     @Test
-    public void testVarargsCollector() throws Throwable {
+    public void testVarargsCollectorNoThrow() throws Throwable {
         MethodType t1 = MethodType.methodType(Object.class, Object.class, Object.class, Object.class, Object.class,
                 Object.class, Object.class, Object.class, Object.class, Object[].class);
 
@@ -92,17 +128,34 @@
 
         MethodHandle target = LOOKUP.findStatic(TestCatchException.class, "m1", t1)
                                     .asVarargsCollector(Object[].class);
-
-        MethodHandle catcher = LOOKUP.findStatic(TestCatchException.class, "m2", t2);
-
+        MethodHandle catcher = LOOKUP.findStatic(TestCatchException.class, "m2", t2)
+                                     .asVarargsCollector(Object[].class);
         MethodHandle gwc = MethodHandles.catchException(target, Exception.class, catcher);
 
-        Object o = new Object();
-        Object[] obj1 = new Object[] { "str" };
+        Object o = masterParam;
+        Object[] obj1 = masterTail;
+
+        Object r2 = gwc.invokeExact(o, o, o, o, o, o, o, o, obj1);
+        assertEquals(r2, obj1);
+    }
+
+    @Test
+    public void testVarargsCollectorThrow() throws Throwable {
+        MethodType t1 = MethodType.methodType(Object.class, Object.class, Object.class, Object.class, Object.class,
+                Object.class, Object.class, Object.class, Object.class, Object[].class);
 
-        Object r1 = target.invokeExact(o, o, o, o, o, o, o, o, obj1);
+        MethodType t2 = t1.insertParameterTypes(0, Exception.class);
+
+        MethodHandle target = LOOKUP.findStatic(TestCatchException.class, "throwEx", t1)
+                                    .asVarargsCollector(Object[].class);
+        MethodHandle catcher = LOOKUP.findStatic(TestCatchException.class, "m2", t2)
+                                     .asVarargsCollector(Object[].class);
+        MethodHandle gwc = MethodHandles.catchException(target, Exception.class, catcher);
+
+        Object o = masterParam;
+        Object[] obj1 = masterTail;
+
         Object r2 = gwc.invokeExact(o, o, o, o, o, o, o, o, obj1);
-        assertEquals(r1, obj1);
         assertEquals(r2, obj1);
     }
 
@@ -110,7 +163,8 @@
         TestCatchException test = new TestCatchException();
         test.testNoThrowPath();
         test.testThrowPath();
-        test.testVarargsCollector();
+        test.testVarargsCollectorNoThrow();
+        test.testVarargsCollectorThrow();
         System.out.println("TEST PASSED");
     }
 }