changeset 2201:4fa835472e3c

8028739: javac generates incorrect descriptor for MethodHandle::invoke Summary: introduce special handling for signature polymorphic methods Reviewed-by: jjg
author rfield
date Fri, 22 Nov 2013 17:07:35 -0800
parents ef44a2971cb1
children 7ef88faaa16c
files src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java test/tools/javac/lambda/methodReferenceExecution/MethodReferenceTestMethodHandle.java
diffstat 2 files changed, 126 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Wed Nov 20 10:53:38 2013 -0800
+++ b/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Fri Nov 22 17:07:35 2013 -0800
@@ -357,9 +357,11 @@
 
         //first determine the method symbol to be used to generate the sam instance
         //this is either the method reference symbol, or the bridged reference symbol
-        Symbol refSym = localContext.needsBridge() ?
-            localContext.bridgeSym :
-            tree.sym;
+        Symbol refSym = localContext.needsBridge()
+                ? localContext.bridgeSym
+                : localContext.isSignaturePolymorphic()
+                ? localContext.sigPolySym
+                : tree.sym;
 
         //build the bridge method, if needed
         if (localContext.needsBridge()) {
@@ -1995,6 +1997,7 @@
 
             final boolean isSuper;
             final Symbol bridgeSym;
+            final Symbol sigPolySym;
 
             ReferenceTranslationContext(JCMemberReference tree) {
                 super(tree);
@@ -2004,6 +2007,12 @@
                                               referenceBridgeName(), null,
                                               owner.enclClass())
                         : null;
+                this.sigPolySym = isSignaturePolymorphic()
+                        ? makePrivateSyntheticMethod(tree.sym.flags(),
+                                              tree.sym.name,
+                                              bridgedRefSig(),
+                                              tree.sym.enclClass())
+                        : null;
                 if (dumpLambdaToMethodStats) {
                     String key = bridgeSym == null ?
                             "mref.stat" : "mref.stat.1";
@@ -2106,6 +2115,15 @@
             }
 
             /**
+             * Signature polymorphic methods need special handling.
+             * e.g. MethodHandle.invoke() MethodHandle.invokeExact()
+             */
+            final boolean isSignaturePolymorphic() {
+                return  tree.sym.kind == MTH &&
+                        types.isSignaturePolymorphic((MethodSymbol)tree.sym);
+            }
+
+            /**
              * Does this reference needs a bridge (i.e. var args need to be
              * expanded or "super" is used)
              */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/lambda/methodReferenceExecution/MethodReferenceTestMethodHandle.java	Fri Nov 22 17:07:35 2013 -0800
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8028739
+ * @summary javac generates incorrect descriptor for MethodHandle::invoke
+ * @run testng MethodReferenceTestMethodHandle
+ */
+
+import java.lang.invoke.*;
+import java.util.*;
+
+import org.testng.annotations.Test;
+import static org.testng.Assert.assertEquals;
+
+@Test
+public class MethodReferenceTestMethodHandle {
+
+  MethodHandles.Lookup lookup = MethodHandles.lookup();
+
+  interface ReplaceItf {
+      Object apply(String a, char b, char c) throws Throwable;
+  }
+
+  interface FormatItf {
+      Object apply(String a, Object... args) throws Throwable;
+  }
+
+  interface AddItf {
+      void apply(List st, int idx, Object v) throws Throwable;
+  }
+
+  public void testVirtual() throws Throwable {
+
+      MethodType mt = MethodType.methodType(String.class, char.class, char.class);
+      MethodHandle ms = lookup.findVirtual(String.class, "replace", mt);
+
+      // --- String.replace(String, char, char) ---
+
+      assertEquals("oome otring to oearch", ms.invoke("some string to search", 's', 'o'));
+
+      ReplaceItf f1 = (a, b, c) -> ms.invoke(a,b,c);
+      assertEquals("oome otring to oearch", f1.apply("some string to search", 's', 'o'));
+
+      ReplaceItf f2 = ms::invoke;
+      assertEquals("oome otring to oearch", f2.apply("some string to search", 's', 'o'));
+      assertEquals("oome otring to oearch", f2.apply("some string to search", new Character('s'), 'o'));
+      assertEquals("oome otring to oearch", ((ReplaceItf) ms::invoke).apply("some string to search", 's', 'o'));
+  }
+
+  public void testStatic() throws Throwable {
+      MethodType fmt = MethodType.methodType(String.class, String.class, (new Object[1]).getClass());
+      MethodHandle fms = lookup.findStatic(String.class, "format", fmt);
+
+      // --- String.format(String, Object...) ---
+
+      assertEquals("Testing One 2 3", fms.invoke("Testing %s %d %x", "One", new Integer(2), 3));
+
+      FormatItf ff2 = fms::invoke;
+      assertEquals("Testing One 2 3", ff2.apply("Testing %s %d %x", "One", new Integer(2), 3));
+      assertEquals("Testing One 2 3", ((FormatItf) fms::invoke).apply("Testing %s %d %x", "One", new Integer(2), 3));
+      assertEquals("Testing One 2 3 four", ff2.apply("Testing %s %d %x %s", "One", new Integer(2), 3, "four"));
+  }
+
+  public void testVoid() throws Throwable {
+      MethodType pmt = MethodType.methodType(void.class, int.class, Object.class);
+      MethodHandle pms = lookup.findVirtual(List.class, "add", pmt);
+      List<String> list = new ArrayList<>();
+
+      // --- List.add(int,String) ---
+
+      pms.invoke(list, 0, "Hi");
+
+      AddItf pf2 = pms::invoke;
+      pf2.apply(list, 1, "there");
+      AddItf pf3 = pms::invokeExact;
+      pf3.apply(list, 2, "you");
+      assertEquals("Hi", list.get(0));
+      assertEquals("there", list.get(1));
+      assertEquals("you", list.get(2));
+   }
+}