1 /* 2 * Copyright (c) 2017, 2018, 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 nested dynamic constant declarations that are recursive 28 * @compile CondyNestedTest_Code.jcod 29 * @run testng CondyNestedTest 30 */ 31 32 import org.testng.Assert; 33 import org.testng.annotations.BeforeClass; 34 import org.testng.annotations.Test; 35 36 import java.lang.reflect.InvocationTargetException; 37 import java.lang.reflect.Method; 38 39 public class CondyNestedTest { 40 41 static final Class[] THROWABLES = {InvocationTargetException.class, StackOverflowError.class}; 42 43 Class<?> c; 44 45 // Add the following annotations to the test description if uncommenting the 46 // following code 47 // 48 // * @library /lib/testlibrary/bytecode 49 // * @build jdk.experimental.bytecode.BasicClassBuilder 50 // 51 // static final MethodHandles.Lookup L = MethodHandles.lookup(); 52 // 53 // /** 54 // * Generate class file bytes for a class named CondyNestedTest_Code 55 // * whose bytes are converted to a jcod file: 56 // * 57 // * java -jar asmtools.jar jdec CondyNestedTest_Code.class > 58 // * CondyNestedTest_Code.jcod 59 // * 60 // * which was then edited so that dynamic constant declarations are 61 // * recursive both for an ldc or invokedynamic (specifically declaring a 62 // * BSM+attributes whose static argument is a dynamic constant 63 // * that refers to the same BSM+attributes). 64 // */ 65 // public static byte[] generator() throws Exception { 66 // String genClassName = L.lookupClass().getSimpleName() + "_Code"; 67 // String bsmDescriptor = MethodType.methodType(Object.class, MethodHandles.Lookup.class, String.class, Object.class, Object.class).toMethodDescriptorString(); 68 // String bsmIndyDescriptor = MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class, Object.class, Object.class).toMethodDescriptorString(); 69 // 70 // byte[] byteArray = new BasicClassBuilder(genClassName, 55, 0) 71 // .withSuperclass("java/lang/Object") 72 // .withMethod("<init>", "()V", M -> 73 // M.withFlags(Flag.ACC_PUBLIC) 74 // .withCode(TypedCodeBuilder::new, C -> 75 // C.aload_0().invokespecial("java/lang/Object", "<init>", "()V", false).return_() 76 // )) 77 // .withMethod("main", "([Ljava/lang/String;)V", M -> 78 // M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC) 79 // .withCode(TypedCodeBuilder::new, C -> { 80 // C.aload_0().iconst_0().aaload(); 81 // C.invokevirtual("java/lang/String", "intern", "()Ljava/lang/String;", false); 82 // C.astore_1(); 83 // 84 // C.aload_1(); 85 // C.ldc("condy_bsm_condy_bsm"); 86 // C.ifcmp(TypeTag.A, MacroCodeBuilder.CondKind.NE, "CASE1"); 87 // C.invokestatic(genClassName, "condy_bsm_condy_bsm", "()Ljava/lang/Object;", false).return_(); 88 // 89 // C.label("CASE1"); 90 // C.aload_1(); 91 // C.ldc("indy_bsmIndy_condy_bsm"); 92 // C.ifcmp(TypeTag.A, MacroCodeBuilder.CondKind.NE, "CASE2"); 93 // C.invokestatic(genClassName, "indy_bsmIndy_condy_bsm", "()Ljava/lang/Object;", false).return_(); 94 // 95 // C.label("CASE2"); 96 // C.aload_1(); 97 // C.ldc("indy_bsm_condy_bsm"); 98 // C.ifcmp(TypeTag.A, MacroCodeBuilder.CondKind.NE, "CASE3"); 99 // C.invokestatic(genClassName, "indy_bsm_condy_bsm", "()Ljava/lang/Object;", false).return_(); 100 // 101 // C.label("CASE3"); 102 // C.return_(); 103 // })) 104 // .withMethod("bsm", bsmDescriptor, M -> 105 // M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC) 106 // .withCode(TypedCodeBuilder::new, C -> { 107 // C.aload_2(); 108 // C.instanceof_("java/lang/invoke/MethodType"); 109 // C.iconst_0(); 110 // C.ifcmp(TypeTag.I, MacroCodeBuilder.CondKind.EQ, "CONDY"); 111 // C.new_("java/lang/invoke/ConstantCallSite").dup(); 112 // C.ldc("java/lang/String", PoolHelper::putClass); 113 // C.aload_1(); 114 // C.invokestatic("java/lang/invoke/MethodHandles", "constant", "(Ljava/lang/Class;Ljava/lang/Object;)Ljava/lang/invoke/MethodHandle;", false); 115 // C.invokespecial("java/lang/invoke/ConstantCallSite", "<init>", "(Ljava/lang/invoke/MethodHandle;)V", false); 116 // C.areturn(); 117 // C.label("CONDY"); 118 // C.aload_1().areturn(); 119 // })) 120 // .withMethod("bsmIndy", bsmIndyDescriptor, M -> 121 // M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC) 122 // .withCode(TypedCodeBuilder::new, C -> { 123 // C.new_("java/lang/invoke/ConstantCallSite").dup(); 124 // C.ldc("java/lang/String", PoolHelper::putClass); 125 // C.aload_1(); 126 // C.invokestatic("java/lang/invoke/MethodHandles", "constant", "(Ljava/lang/Class;Ljava/lang/Object;)Ljava/lang/invoke/MethodHandle;", false); 127 // C.invokespecial("java/lang/invoke/ConstantCallSite", "<init>", "(Ljava/lang/invoke/MethodHandle;)V", false); 128 // C.areturn(); 129 // })) 130 // .withMethod("condy_bsm_condy_bsm", "()Ljava/lang/Object;", M -> 131 // M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC) 132 // .withCode(TypedCodeBuilder::new, C -> 133 // C.ldc("name", "Ljava/lang/String;", genClassName, "bsm", bsmDescriptor, 134 // S -> S.add(null, (P, v) -> { 135 // return P.putDynamicConstant("name", "Ljava/lang/String;", genClassName, "bsm", bsmDescriptor, 136 // S2 -> S2.add("DUMMY_ARG", PoolHelper::putString)); 137 // })) 138 // .areturn())) 139 // .withMethod("indy_bsmIndy_condy_bsm", "()Ljava/lang/Object;", M -> 140 // M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC) 141 // .withCode(TypedCodeBuilder::new, C -> 142 // C.invokedynamic("name", "()Ljava/lang/String;", genClassName, "bsmIndy", bsmIndyDescriptor, 143 // S -> S.add(null, (P, v) -> { 144 // return P.putDynamicConstant("name", "Ljava/lang/String;", genClassName, "bsm", bsmDescriptor, 145 // S2 -> S2.add("DUMMY_ARG", PoolHelper::putString)); 146 // })) 147 // .areturn())) 148 // .withMethod("indy_bsm_condy_bsm", "()Ljava/lang/Object;", M -> 149 // M.withFlags(Flag.ACC_PUBLIC, Flag.ACC_STATIC) 150 // .withCode(TypedCodeBuilder::new, C -> 151 // C.invokedynamic("name", "()Ljava/lang/String;", genClassName, "bsm", bsmDescriptor, 152 // S -> S.add(null, (P, v) -> { 153 // return P.putDynamicConstant("name", "Ljava/lang/String;", genClassName, "bsm", bsmDescriptor, 154 // S2 -> S2.add("DUMMY_ARG", PoolHelper::putString)); 155 // })) 156 // .areturn())) 157 // .build(); 158 // 159 // File f = new File(genClassName + ".class"); 160 // if (f.getParentFile() != null) { 161 // f.getParentFile().mkdirs(); 162 // } 163 // new FileOutputStream(f).write(byteArray); 164 // return byteArray; 165 // 166 // } 167 168 static void test(Method m, Class<? extends Throwable>... ts) { 169 Throwable caught = null; 170 try { 171 m.invoke(null); 172 } 173 catch (Throwable t) { 174 caught = t; 175 } 176 177 if (caught == null) { 178 Assert.fail("Throwable expected"); 179 } 180 181 String actualMessage = null; 182 for (int i = 0; i < ts.length; i++) { 183 actualMessage = caught.getMessage(); 184 Assert.assertNotNull(caught); 185 Assert.assertTrue(ts[i].isAssignableFrom(caught.getClass())); 186 caught = caught.getCause(); 187 } 188 } 189 190 @BeforeClass 191 public void findClass() throws Exception { 192 c = Class.forName("CondyNestedTest_Code"); 193 } 194 195 /** 196 * Testing an ldc of a dynamic constant, C say, with a BSM whose static 197 * argument is C. 198 */ 199 @Test 200 public void testCondyBsmCondyBsm() throws Exception { 201 test("condy_bsm_condy_bsm", THROWABLES); 202 } 203 204 /** 205 * Testing an invokedynamic with a BSM whose static argument is a constant 206 * dynamic, C say, with a BSM whose static argument is C. 207 */ 208 @Test 209 public void testIndyBsmIndyCondyBsm() throws Exception { 210 test("indy_bsmIndy_condy_bsm", THROWABLES); 211 } 212 213 /** 214 * Testing an invokedynamic with a BSM, B say, whose static argument is 215 * a dynamic constant, C say, that uses BSM B. 216 */ 217 @Test 218 public void testIndyBsmCondyBsm() throws Exception { 219 test("indy_bsm_condy_bsm", THROWABLES); 220 } 221 222 void test(String methodName, Class<? extends Throwable>... ts) throws Exception { 223 Method m = c.getMethod(methodName); 224 m.setAccessible(true); 225 test(m, ts); 226 } 227 228 }