test/jdk/java/lang/invoke/condy/CondyRepeatFailedResolution.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 8186211
       
    27  * @summary Test basic invocation of multiple ldc's of the same dynamic constant that fail resolution
       
    28  * @requires os.arch == "x86_64"
       
    29  * @library /lib/testlibrary/bytecode /java/lang/invoke/common
       
    30  * @build jdk.experimental.bytecode.BasicClassBuilder
       
    31  * @run testng CondyRepeatFailedResolution
       
    32  * @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyRepeatFailedResolution
       
    33  */
       
    34 
       
    35 import jdk.experimental.bytecode.BasicClassBuilder;
       
    36 import jdk.experimental.bytecode.Flag;
       
    37 import jdk.experimental.bytecode.TypedCodeBuilder;
       
    38 import org.testng.Assert;
       
    39 import org.testng.annotations.BeforeClass;
       
    40 import org.testng.annotations.Test;
       
    41 
       
    42 import java.io.File;
       
    43 import java.io.FileOutputStream;
       
    44 import java.lang.invoke.MethodHandles;
       
    45 import java.lang.invoke.MethodType;
       
    46 import java.lang.reflect.InvocationTargetException;
       
    47 import java.lang.reflect.Method;
       
    48 
       
    49 @Test
       
    50 public class CondyRepeatFailedResolution {
       
    51     // Counter used to determine if a given BSM is invoked more than once
       
    52     static int bsm_called = 0;
       
    53 
       
    54     // Generated class with methods containing condy ldc
       
    55     Class<?> gc;
       
    56 
       
    57     // Bootstrap method used to represent primitive values
       
    58     // that cannot be represented directly in the constant pool,
       
    59     // such as byte, and for completeness of testing primitive values
       
    60     // that can be represented directly, such as double or long that
       
    61     // take two slots
       
    62     public static Object intConversion(MethodHandles.Lookup l,
       
    63                                        String constantName,
       
    64                                        Class<?> constantType,
       
    65                                        int value) throws Throwable {
       
    66         ++bsm_called;
       
    67         // replace constantName with a bogus value to trigger failed resolution
       
    68         constantName = "Foo";
       
    69 
       
    70         switch (constantName) {
       
    71             case "B":
       
    72                 return (byte) value;
       
    73             case "C":
       
    74                 return (char) value;
       
    75             case "D":
       
    76                 return (double) value;
       
    77             case "F":
       
    78                 return (float) value;
       
    79             case "I":
       
    80                 return value;
       
    81             case "J":
       
    82                 return (long) value;
       
    83             case "S":
       
    84                 return (short) value;
       
    85             case "Z":
       
    86                 return value > 0;
       
    87             case "nullRef":
       
    88                 return null;
       
    89             case "string":
       
    90                 return "string";
       
    91             case "stringArray":
       
    92                 return new String[]{"string", "string"};
       
    93             default:
       
    94                 throw new BootstrapMethodError("Failure to generate a dynamic constant");
       
    95         }
       
    96     }
       
    97 
       
    98     @BeforeClass
       
    99     public void generateClass() throws Exception {
       
   100         String genClassName = CondyRepeatFailedResolution.class.getSimpleName() + "$Code";
       
   101         String bsmClassName = CondyRepeatFailedResolution.class.getCanonicalName().replace('.', '/');
       
   102         String bsmMethodName = "intConversion";
       
   103         String bsmDescriptor = MethodType.methodType(Object.class, MethodHandles.Lookup.class,
       
   104                                                      String.class, Class.class, int.class).toMethodDescriptorString();
       
   105 
       
   106         byte[] byteArray = new BasicClassBuilder(genClassName, 55, 0)
       
   107                 .withSuperclass("java/lang/Object")
       
   108                 .withMethod("<init>", "()V", M ->
       
   109                         M.withFlags(Flag.ACC_PUBLIC)
       
   110                                 .withCode(TypedCodeBuilder::new, C ->
       
   111                                         C.aload_0().invokespecial("java/lang/Object", "<init>", "()V", false).return_()
       
   112                                 ))
       
   113                 .withMethod("B", "()B", M ->
       
   114                         M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC)
       
   115                                 .withCode(TypedCodeBuilder::new, C ->
       
   116                                         C.ldc("B", "B", bsmClassName, bsmMethodName, bsmDescriptor,
       
   117                                               S -> S.add(Byte.MAX_VALUE))
       
   118                                                 .ireturn()
       
   119                                 ))
       
   120                 .withMethod("C", "()C", M ->
       
   121                         M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC)
       
   122                                 .withCode(TypedCodeBuilder::new, C ->
       
   123                                         C.ldc("C", "C", bsmClassName, bsmMethodName, bsmDescriptor,
       
   124                                               S -> S.add(Character.MAX_VALUE))
       
   125                                                 .ireturn()
       
   126                                 ))
       
   127                 .withMethod("D", "()D", M ->
       
   128                         M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC)
       
   129                                 .withCode(TypedCodeBuilder::new, C ->
       
   130                                         C.ldc("D", "D", bsmClassName, bsmMethodName, bsmDescriptor,
       
   131                                               S -> S.add(Integer.MAX_VALUE))
       
   132                                                 .dreturn()
       
   133                                 ))
       
   134                 .withMethod("D_AsType", "()D", M ->
       
   135                         M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC)
       
   136                                 .withCode(TypedCodeBuilder::new, C ->
       
   137                                         C.ldc("I", "D", bsmClassName, bsmMethodName, bsmDescriptor,
       
   138                                               S -> S.add(Integer.MAX_VALUE))
       
   139                                                 .dreturn()
       
   140                                 ))
       
   141                 .withMethod("F", "()F", M ->
       
   142                         M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC)
       
   143                                 .withCode(TypedCodeBuilder::new, C ->
       
   144                                         C.ldc("F", "F", bsmClassName, bsmMethodName, bsmDescriptor,
       
   145                                               S -> S.add(Integer.MAX_VALUE))
       
   146                                                 .freturn()
       
   147                                 ))
       
   148                 .withMethod("F_AsType", "()F", M ->
       
   149                         M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC)
       
   150                                 .withCode(TypedCodeBuilder::new, C ->
       
   151                                         C.ldc("I", "F", bsmClassName, bsmMethodName, bsmDescriptor,
       
   152                                               S -> S.add(Integer.MAX_VALUE))
       
   153                                                 .freturn()
       
   154                                 ))
       
   155                 .withMethod("I", "()I", M ->
       
   156                         M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC)
       
   157                                 .withCode(TypedCodeBuilder::new, C ->
       
   158                                         C.ldc("I", "I", bsmClassName, bsmMethodName, bsmDescriptor,
       
   159                                               S -> S.add(Integer.MAX_VALUE))
       
   160                                                 .ireturn()
       
   161                                 ))
       
   162                 .withMethod("J", "()J", M ->
       
   163                         M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC)
       
   164                                 .withCode(TypedCodeBuilder::new, C ->
       
   165                                         C.ldc("J", "J", bsmClassName, bsmMethodName, bsmDescriptor,
       
   166                                               S -> S.add(Integer.MAX_VALUE))
       
   167                                                 .lreturn()
       
   168                                 ))
       
   169                 .withMethod("J_AsType", "()J", M ->
       
   170                         M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC)
       
   171                                 .withCode(TypedCodeBuilder::new, C ->
       
   172                                         C.ldc("I", "J", bsmClassName, bsmMethodName, bsmDescriptor,
       
   173                                               S -> S.add(Integer.MAX_VALUE))
       
   174                                                 .lreturn()
       
   175                                 ))
       
   176                 .withMethod("S", "()S", M ->
       
   177                         M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC)
       
   178                                 .withCode(TypedCodeBuilder::new, C ->
       
   179                                         C.ldc("S", "S", bsmClassName, bsmMethodName, bsmDescriptor,
       
   180                                               S -> S.add(Short.MAX_VALUE))
       
   181                                                 .ireturn()
       
   182                                 ))
       
   183                 .withMethod("Z_F", "()Z", M ->
       
   184                         M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC)
       
   185                                 .withCode(TypedCodeBuilder::new, C ->
       
   186                                         C.ldc("Z", "Z", bsmClassName, bsmMethodName, bsmDescriptor,
       
   187                                               S -> S.add(0))
       
   188                                                 .ireturn()
       
   189                                 ))
       
   190                 .withMethod("Z_T", "()Z", M ->
       
   191                         M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC)
       
   192                                 .withCode(TypedCodeBuilder::new, C ->
       
   193                                         C.ldc("Z", "Z", bsmClassName, bsmMethodName, bsmDescriptor,
       
   194                                               S -> S.add(1))
       
   195                                                 .ireturn()
       
   196                                 ))
       
   197                 .withMethod("null", "()Ljava/lang/Object;", M ->
       
   198                         M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC)
       
   199                                 .withCode(TypedCodeBuilder::new, C ->
       
   200                                         C.ldc("nullRef", "Ljava/lang/Object;", bsmClassName, bsmMethodName, bsmDescriptor,
       
   201                                               S -> S.add(Integer.MAX_VALUE))
       
   202                                                 .areturn()
       
   203                                 ))
       
   204                 .withMethod("string", "()Ljava/lang/String;", M ->
       
   205                         M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC)
       
   206                                 .withCode(TypedCodeBuilder::new, C ->
       
   207                                         C.ldc("string", "Ljava/lang/String;", bsmClassName, bsmMethodName, bsmDescriptor,
       
   208                                               S -> S.add(Integer.MAX_VALUE))
       
   209                                                 .areturn()
       
   210                                 ))
       
   211                 .withMethod("stringArray", "()[Ljava/lang/String;", M ->
       
   212                         M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC)
       
   213                                 .withCode(TypedCodeBuilder::new, C ->
       
   214                                         C.ldc("stringArray", "[Ljava/lang/String;", bsmClassName, bsmMethodName, bsmDescriptor,
       
   215                                               S -> S.add(Integer.MAX_VALUE))
       
   216                                                 .areturn()
       
   217                                 ))
       
   218                 .build();
       
   219 
       
   220         // For debugging purposes
       
   221         new FileOutputStream(new File(genClassName + ".class")).write(byteArray);
       
   222 
       
   223         gc = MethodHandles.lookup().defineClass(byteArray);
       
   224     }
       
   225 
       
   226     @Test
       
   227     public void testPrimitives() throws Exception {
       
   228         testConstants();
       
   229     }
       
   230 
       
   231     @Test
       
   232     public void testRefs() throws Exception {
       
   233         testConstant("string", "string");
       
   234         testConstant("stringArray", new String[]{"string", "string"});
       
   235     }
       
   236 
       
   237     void testConstants() throws Exception {
       
   238         // Note: for the _asType methods the BSM returns an int which is
       
   239         // then converted by an asType transformation
       
   240 
       
   241         testConstant("B", Byte.MAX_VALUE);
       
   242         testConstant("C", Character.MAX_VALUE);
       
   243         testConstant("D", (double) Integer.MAX_VALUE);
       
   244         testConstant("D_AsType", (double) Integer.MAX_VALUE);
       
   245         testConstant("F", (float) Integer.MAX_VALUE);
       
   246         testConstant("F_AsType", (float) Integer.MAX_VALUE);
       
   247         testConstant("I", Integer.MAX_VALUE);
       
   248         testConstant("J", (long) Integer.MAX_VALUE);
       
   249         testConstant("J_AsType", (long) Integer.MAX_VALUE);
       
   250         testConstant("S", Short.MAX_VALUE);
       
   251         testConstant("Z_F", false);
       
   252         testConstant("Z_T", true);
       
   253         testConstant("null", null);
       
   254     }
       
   255 
       
   256     void testConstant(String name, Object expected) throws Exception {
       
   257         Method m = gc.getDeclaredMethod(name);
       
   258 
       
   259         bsm_called = 0;
       
   260         try {
       
   261             Object r1 = m.invoke(null);
       
   262             Assert.fail("InvocationTargetException expected to be thrown after first invocation");
       
   263         } catch (InvocationTargetException e1) {
       
   264             // bsm_called should have been incremented prior to the exception
       
   265             Assert.assertEquals(bsm_called, 1);
       
   266             Assert.assertTrue(e1.getCause() instanceof BootstrapMethodError);
       
   267             // Try invoking method again to ensure that the bootstrap
       
   268             // method is not invoked twice and a resolution failure
       
   269             // results.
       
   270             try {
       
   271                 Object r2 = m.invoke(null);
       
   272                 Assert.fail("InvocationTargetException expected to be thrown after second invocation");
       
   273             } catch (InvocationTargetException e2) {
       
   274                 // bsm_called should remain at 1 since the bootstrap
       
   275                 // method should not have been invoked.
       
   276                 Assert.assertEquals(bsm_called, 1);
       
   277                 Assert.assertTrue(e2.getCause() instanceof BootstrapMethodError);
       
   278             } catch (Throwable t2) {
       
   279                 Assert.fail("InvocationTargetException expected to be thrown");
       
   280             }
       
   281         } catch (Throwable t1) {
       
   282                 Assert.fail("InvocationTargetException expected to be thrown");
       
   283         }
       
   284     }
       
   285 }