jdk/test/java/lang/invoke/lambda/MetafactoryDescriptorTest.java
changeset 43700 ee6b5bd26bf9
parent 23049 c66d7e7bcded
equal deleted inserted replaced
43699:9127aa5e51a7 43700:ee6b5bd26bf9
       
     1 /*
       
     2  * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.
       
     8  *
       
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    12  * version 2 for more details (a copy is included in the LICENSE file that
       
    13  * accompanied this code).
       
    14  *
       
    15  * You should have received a copy of the GNU General Public License version
       
    16  * 2 along with this work; if not, write to the Free Software Foundation,
       
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    18  *
       
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    20  * or visit www.oracle.com if you need additional information or have any
       
    21  * questions.
       
    22  */
       
    23 
       
    24 /*
       
    25  * @test
       
    26  * @bug 8035776 8173587
       
    27  * @summary metafactory should fail if instantiatedMethodType does not match sam/bridge descriptors
       
    28  */
       
    29 import java.lang.invoke.*;
       
    30 import java.util.*;
       
    31 
       
    32 public class MetafactoryDescriptorTest {
       
    33 
       
    34     static final MethodHandles.Lookup lookup = MethodHandles.lookup();
       
    35 
       
    36     static MethodType mt(Class<?> ret, Class<?>... params) {
       
    37         return MethodType.methodType(ret, params);
       
    38     }
       
    39 
       
    40     public interface I {}
       
    41 
       
    42     public static class C {
       
    43         public static void m_void(String arg) {}
       
    44         public static boolean m_boolean(String arg) { return true; }
       
    45         public static char m_char(String arg) { return 'x'; }
       
    46         public static byte m_byte(String arg) { return 12; }
       
    47         public static short m_short(String arg) { return 12; }
       
    48         public static int m_int(String arg) { return 12; }
       
    49         public static long m_long(String arg) { return 12; }
       
    50         public static float m_float(String arg) { return 12; }
       
    51         public static double m_double(String arg) { return 12; }
       
    52         public static String m_String(String arg) { return ""; }
       
    53         public static Integer m_Integer(String arg) { return 23; }
       
    54         public static Object m_Object(String arg) { return new Object(); }
       
    55 
       
    56         public static String n_boolean(boolean arg) { return ""; }
       
    57         public static String n_char(char arg) { return ""; }
       
    58         public static String n_byte(byte arg) { return ""; }
       
    59         public static String n_short(short arg) { return ""; }
       
    60         public static String n_int(int arg) { return ""; }
       
    61         public static String n_long(long arg) { return ""; }
       
    62         public static String n_float(float arg) { return ""; }
       
    63         public static String n_double(double arg) { return ""; }
       
    64         public static String n_String(String arg) { return ""; }
       
    65         public static String n_Integer(Integer arg) { return ""; }
       
    66         public static String n_Object(Object arg) { return ""; }
       
    67 
       
    68         public static MethodHandle getM(Class<?> c) {
       
    69             try {
       
    70                 return lookup.findStatic(C.class, "m_" + c.getSimpleName(), mt(c, String.class));
       
    71             }
       
    72             catch (NoSuchMethodException | IllegalAccessException e) {
       
    73                 throw new RuntimeException(e);
       
    74             }
       
    75         }
       
    76 
       
    77         public static MethodHandle getN(Class<?> c) {
       
    78             if (c == void.class) return null;
       
    79             try {
       
    80                 return lookup.findStatic(C.class, "n_" + c.getSimpleName(), mt(String.class, c));
       
    81             }
       
    82             catch (NoSuchMethodException | IllegalAccessException e) {
       
    83                 throw new RuntimeException(e);
       
    84             }
       
    85         }
       
    86 
       
    87     }
       
    88 
       
    89     public static void main(String... args) {
       
    90         Class<?>[] t = { void.class, boolean.class, char.class,
       
    91                          byte.class, short.class, int.class, long.class, float.class, double.class,
       
    92                          String.class, Integer.class, Object.class };
       
    93 
       
    94         for (int i = 0; i < t.length; i++) {
       
    95             MethodHandle m = C.getM(t[i]);
       
    96             MethodHandle n = C.getN(t[i]); // null for void.class
       
    97             for (int j = 0; j < t.length; j++) {
       
    98                 boolean correctRet = t[j].isAssignableFrom(t[i]) || conversions.contains(t[i], t[j]);
       
    99                 test(correctRet, m, mt(t[i], String.class), mt(t[j], String.class));
       
   100                 testBridge(correctRet, m, mt(t[i], String.class), mt(t[i], String.class),
       
   101                            mt(t[j], Object.class));
       
   102                 testBridge(correctRet, m, mt(t[i], String.class), mt(t[i], String.class),
       
   103                            mt(t[i], CharSequence.class), mt(t[j], Object.class));
       
   104 
       
   105                 if (t[i] != void.class && t[j] != void.class) {
       
   106                     boolean correctParam = t[j].isAssignableFrom(t[i]);
       
   107                     test(correctParam, n, mt(String.class, t[i]), mt(String.class, t[j]));
       
   108                     testBridge(correctParam, n, mt(String.class, t[i]), mt(String.class, t[i]),
       
   109                             mt(Object.class, t[j]));
       
   110                     testBridge(correctParam, n, mt(String.class, t[i]), mt(String.class, t[i]),
       
   111                             mt(CharSequence.class, t[i]), mt(Object.class, t[j]));
       
   112                 }
       
   113 
       
   114             }
       
   115         }
       
   116     }
       
   117 
       
   118     static void test(boolean correct, MethodHandle mh, MethodType instMT, MethodType samMT) {
       
   119         tryMetafactory(correct, mh, instMT, samMT);
       
   120         tryAltMetafactory(correct, mh, instMT, samMT);
       
   121     }
       
   122 
       
   123     static void testBridge(boolean correct, MethodHandle mh, MethodType instMT, MethodType samMT, MethodType... bridgeMTs) {
       
   124         tryAltMetafactory(correct, mh, instMT, samMT, bridgeMTs);
       
   125     }
       
   126 
       
   127     static void tryMetafactory(boolean correct, MethodHandle mh, MethodType instMT, MethodType samMT) {
       
   128         try {
       
   129             LambdaMetafactory.metafactory(lookup, "run", mt(I.class),
       
   130                                           samMT, mh, instMT);
       
   131             if (!correct) {
       
   132                 throw new AssertionError("Unexpected linkage without error:" +
       
   133                                          " impl=" + mh +
       
   134                                          ", inst=" + instMT +
       
   135                                          ", sam=" + samMT);
       
   136             }
       
   137         }
       
   138         catch (LambdaConversionException e) {
       
   139             if (correct) {
       
   140                 throw new AssertionError("Unexpected linkage error:" +
       
   141                                          " e=" + e +
       
   142                                          ", impl=" + mh +
       
   143                                          ", inst=" + instMT +
       
   144                                          ", sam=" + samMT);
       
   145             }
       
   146         }
       
   147     }
       
   148 
       
   149     static void tryAltMetafactory(boolean correct, MethodHandle mh, MethodType instMT, MethodType samMT,
       
   150                                   MethodType... bridgeMTs) {
       
   151         boolean bridge = bridgeMTs.length > 0;
       
   152         Object[] args = new Object[bridge ? 5+bridgeMTs.length : 4];
       
   153         args[0] = samMT;
       
   154         args[1] = mh;
       
   155         args[2] = instMT;
       
   156         args[3] = bridge ? LambdaMetafactory.FLAG_BRIDGES : 0;
       
   157         if (bridge) {
       
   158             args[4] = bridgeMTs.length;
       
   159             for (int i = 0; i < bridgeMTs.length; i++) args[5+i] = bridgeMTs[i];
       
   160         }
       
   161         try {
       
   162             LambdaMetafactory.altMetafactory(lookup, "run", mt(I.class), args);
       
   163             if (!correct) {
       
   164                 throw new AssertionError("Unexpected linkage without error:" +
       
   165                                          " impl=" + mh +
       
   166                                          ", inst=" + instMT +
       
   167                                          ", sam=" + samMT +
       
   168                                          ", bridges=" + Arrays.toString(bridgeMTs));
       
   169             }
       
   170         }
       
   171         catch (LambdaConversionException e) {
       
   172             if (correct) {
       
   173                 throw new AssertionError("Unexpected linkage error:" +
       
   174                                          " e=" + e +
       
   175                                          ", impl=" + mh +
       
   176                                          ", inst=" + instMT +
       
   177                                          ", sam=" + samMT +
       
   178                                          ", bridges=" + Arrays.toString(bridgeMTs));
       
   179             }
       
   180         }
       
   181     }
       
   182 
       
   183     private static class ConversionTable {
       
   184         private final Map<Class<?>, Set<Class<?>>> pairs = new HashMap<>();
       
   185 
       
   186         public void put(Class<?> from, Class<?> to) {
       
   187             Set<Class<?>> set = pairs.computeIfAbsent(from, f -> new HashSet<>());
       
   188             set.add(to);
       
   189         }
       
   190 
       
   191         public boolean contains(Class<?> from, Class<?> to) {
       
   192             return pairs.containsKey(from) && pairs.get(from).contains(to);
       
   193         }
       
   194     }
       
   195 
       
   196     private static ConversionTable conversions = new ConversionTable();
       
   197     static {
       
   198         conversions.put(char.class, int.class);
       
   199         conversions.put(char.class, long.class);
       
   200         conversions.put(char.class, float.class);
       
   201         conversions.put(char.class, double.class);
       
   202         conversions.put(char.class, Character.class);
       
   203         conversions.put(char.class, Object.class);
       
   204         conversions.put(Character.class, char.class);
       
   205         conversions.put(Character.class, int.class);
       
   206         conversions.put(Character.class, long.class);
       
   207         conversions.put(Character.class, float.class);
       
   208         conversions.put(Character.class, double.class);
       
   209 
       
   210         conversions.put(byte.class, short.class);
       
   211         conversions.put(byte.class, int.class);
       
   212         conversions.put(byte.class, long.class);
       
   213         conversions.put(byte.class, float.class);
       
   214         conversions.put(byte.class, double.class);
       
   215         conversions.put(byte.class, Byte.class);
       
   216         conversions.put(byte.class, Object.class);
       
   217         conversions.put(Byte.class, byte.class);
       
   218         conversions.put(Byte.class, short.class);
       
   219         conversions.put(Byte.class, int.class);
       
   220         conversions.put(Byte.class, long.class);
       
   221         conversions.put(Byte.class, float.class);
       
   222         conversions.put(Byte.class, double.class);
       
   223 
       
   224         conversions.put(short.class, int.class);
       
   225         conversions.put(short.class, long.class);
       
   226         conversions.put(short.class, float.class);
       
   227         conversions.put(short.class, double.class);
       
   228         conversions.put(short.class, Short.class);
       
   229         conversions.put(short.class, Object.class);
       
   230         conversions.put(Short.class, short.class);
       
   231         conversions.put(Short.class, int.class);
       
   232         conversions.put(Short.class, long.class);
       
   233         conversions.put(Short.class, float.class);
       
   234         conversions.put(Short.class, double.class);
       
   235 
       
   236         conversions.put(int.class, long.class);
       
   237         conversions.put(int.class, float.class);
       
   238         conversions.put(int.class, double.class);
       
   239         conversions.put(int.class, Integer.class);
       
   240         conversions.put(int.class, Object.class);
       
   241         conversions.put(Integer.class, int.class);
       
   242         conversions.put(Integer.class, long.class);
       
   243         conversions.put(Integer.class, float.class);
       
   244         conversions.put(Integer.class, double.class);
       
   245 
       
   246         conversions.put(long.class, float.class);
       
   247         conversions.put(long.class, double.class);
       
   248         conversions.put(long.class, Long.class);
       
   249         conversions.put(long.class, Object.class);
       
   250         conversions.put(Long.class, long.class);
       
   251         conversions.put(Long.class, float.class);
       
   252         conversions.put(Long.class, double.class);
       
   253 
       
   254         conversions.put(float.class, double.class);
       
   255         conversions.put(float.class, Float.class);
       
   256         conversions.put(float.class, Object.class);
       
   257         conversions.put(Float.class, float.class);
       
   258         conversions.put(Float.class, double.class);
       
   259 
       
   260         conversions.put(double.class, Double.class);
       
   261         conversions.put(double.class, Object.class);
       
   262         conversions.put(Double.class, double.class);
       
   263 
       
   264         conversions.put(boolean.class, Boolean.class);
       
   265         conversions.put(boolean.class, Object.class);
       
   266         conversions.put(Boolean.class, boolean.class);
       
   267     }
       
   268 
       
   269 }