test/jdk/java/lang/invoke/condy/CondyWrongType.java
changeset 48826 c4d9d1b08e2e
child 48953 67aa88701d46
equal deleted inserted replaced
48825:ef8a98bc71f8 48826:c4d9d1b08e2e
       
     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 8186046
       
    27  * @summary Test bootstrap methods returning the wrong type
       
    28  * @requires os.arch == "x86_64"
       
    29  * @library /lib/testlibrary/bytecode /java/lang/invoke/common
       
    30  * @build jdk.experimental.bytecode.BasicClassBuilder test.java.lang.invoke.lib.InstructionHelper
       
    31  * @run testng CondyWrongType
       
    32  * @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyWrongType
       
    33  */
       
    34 
       
    35 import org.testng.Assert;
       
    36 import org.testng.annotations.DataProvider;
       
    37 import org.testng.annotations.Test;
       
    38 import test.java.lang.invoke.lib.InstructionHelper;
       
    39 
       
    40 import java.lang.invoke.MethodHandle;
       
    41 import java.lang.invoke.MethodHandles;
       
    42 import java.lang.invoke.MethodType;
       
    43 import java.lang.invoke.WrongMethodTypeException;
       
    44 import java.math.BigDecimal;
       
    45 import java.util.ArrayList;
       
    46 import java.util.List;
       
    47 import java.util.Map;
       
    48 
       
    49 import static java.lang.invoke.MethodType.methodType;
       
    50 
       
    51 public class CondyWrongType {
       
    52 
       
    53     @DataProvider
       
    54     public Object[][] primitivesProvider() throws Exception {
       
    55         Map<String, Class<?>> typeMap = Map.of(
       
    56                 "B", byte.class,
       
    57                 "C", char.class,
       
    58                 "D", double.class,
       
    59                 "F", float.class,
       
    60                 "I", int.class,
       
    61                 "J", long.class,
       
    62                 "S", short.class,
       
    63                 "Z", boolean.class
       
    64                 );
       
    65 
       
    66         List<Object[]> cases = new ArrayList<>();
       
    67         for (String name : typeMap.keySet()) {
       
    68             MethodHandle zero = MethodHandles.zero(typeMap.get(name));
       
    69             for (String type : typeMap.keySet()) {
       
    70                 // Use asType transformation to detect if primitive conversion
       
    71                 // is supported from the BSM value type to the dynamic constant type
       
    72                 boolean pass = true;
       
    73                 try {
       
    74                     zero.asType(MethodType.methodType(typeMap.get(type)));
       
    75                 }
       
    76                 catch (WrongMethodTypeException e) {
       
    77                     pass = false;
       
    78                 }
       
    79                 cases.add(new Object[] { name, type, pass});
       
    80             }
       
    81         }
       
    82 
       
    83         return cases.stream().toArray(Object[][]::new);
       
    84     }
       
    85 
       
    86     @Test(dataProvider = "primitivesProvider")
       
    87     public void testPrimitives(String name, String type, boolean pass) {
       
    88         test(name, type, pass);
       
    89     }
       
    90 
       
    91     @Test
       
    92     public void testReferences() {
       
    93         test("String", "Ljava/math/BigDecimal;", false);
       
    94         test("BigDecimal", "Ljava/lang/String;", false);
       
    95     }
       
    96 
       
    97     @Test
       
    98     public void testReferenceAndPrimitives() {
       
    99         test("String", "B", false);
       
   100         test("String", "C", false);
       
   101         test("String", "D", false);
       
   102         test("String", "F", false);
       
   103         test("String", "I", false);
       
   104         test("String", "J", false);
       
   105         test("String", "S", false);
       
   106         test("String", "Z", false);
       
   107     }
       
   108 
       
   109     static void test(String name, String type, boolean pass) {
       
   110         MethodHandle mh = caster(name, type);
       
   111         Throwable caught = null;
       
   112         try {
       
   113             mh.invoke();
       
   114         }
       
   115         catch (Throwable t) {
       
   116             caught = t;
       
   117         }
       
   118 
       
   119         if (caught == null) {
       
   120             if (pass) {
       
   121                 return;
       
   122             }
       
   123             else {
       
   124                 Assert.fail("Throwable expected");
       
   125             }
       
   126         }
       
   127         else if (pass) {
       
   128             Assert.fail("Throwable not expected");
       
   129         }
       
   130 
       
   131         Assert.assertTrue(BootstrapMethodError.class.isAssignableFrom(caught.getClass()));
       
   132         caught = caught.getCause();
       
   133         Assert.assertNotNull(caught);
       
   134         Assert.assertTrue(ClassCastException.class.isAssignableFrom(caught.getClass()));
       
   135     }
       
   136 
       
   137     static Object bsm(MethodHandles.Lookup l, String name, Class<?> type) {
       
   138         switch (name) {
       
   139             case "B":
       
   140                 return (byte) 1;
       
   141             case "C":
       
   142                 return 'A';
       
   143             case "D":
       
   144                 return 1.0;
       
   145             case "F":
       
   146                 return 1.0f;
       
   147             case "I":
       
   148                 return 1;
       
   149             case "J":
       
   150                 return 1L;
       
   151             case "S":
       
   152                 return (short) 1;
       
   153             case "Z":
       
   154                 return true;
       
   155             case "String":
       
   156                 return "string";
       
   157             case "BigDecimal":
       
   158                 return BigDecimal.ONE;
       
   159             default:
       
   160                 throw new UnsupportedOperationException();
       
   161         }
       
   162     }
       
   163 
       
   164     static MethodHandle caster(String name, String type) {
       
   165         try {
       
   166             return InstructionHelper.ldcDynamicConstant(
       
   167                     MethodHandles.lookup(),
       
   168                     name, type,
       
   169                     "bsm", methodType(Object.class, MethodHandles.Lookup.class, String.class, Class.class).toMethodDescriptorString(),
       
   170                     S -> { });
       
   171         } catch (Exception e) {
       
   172             throw new Error(e);
       
   173         }
       
   174     }
       
   175 }