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 8195694 27 * @summary Test dynamic constant bootstraps 28 * @library /lib/testlibrary/bytecode /java/lang/invoke/common 29 * @build jdk.experimental.bytecode.BasicClassBuilder test.java.lang.invoke.lib.InstructionHelper 30 * @run testng ConstantBootstrapsTest 31 */ 32 33 import jdk.experimental.bytecode.PoolHelper; 34 import org.testng.annotations.Test; 35 import test.java.lang.invoke.lib.InstructionHelper; 36 37 import java.lang.invoke.ConstantBootstraps; 38 import java.lang.invoke.MethodHandle; 39 import java.lang.invoke.MethodHandleInfo; 40 import java.lang.invoke.MethodHandles; 41 import java.lang.invoke.MethodType; 42 import java.lang.invoke.VarHandle; 43 import java.lang.invoke.WrongMethodTypeException; 44 import java.math.BigInteger; 45 import java.util.Collection; 46 import java.util.List; 47 import java.util.Map; 48 49 import static org.testng.Assert.assertEquals; 50 import static org.testng.Assert.assertNull; 51 52 @Test 53 public class ConstantBootstrapsTest { 54 static final MethodHandles.Lookup L = MethodHandles.lookup(); 55 56 static MethodType lookupMT(Class<?> ret, Class<?>... params) { 57 return MethodType.methodType(ret, MethodHandles.Lookup.class, String.class, Class.class). 58 appendParameterTypes(params); 59 } 60 61 public void testNullConstant() throws Throwable { 62 var handle = InstructionHelper.ldcDynamicConstant(L, "_", Object.class, 63 ConstantBootstraps.class, "nullConstant", lookupMT(Object.class), 64 S -> {}); 65 assertNull(handle.invoke()); 66 67 handle = InstructionHelper.ldcDynamicConstant(L, "_", MethodType.class, 68 ConstantBootstraps.class, "nullConstant", lookupMT(Object.class), 69 S -> {}); 70 assertNull(handle.invoke()); 71 } 72 73 @Test(expectedExceptions = IllegalArgumentException.class) 74 public void testNullConstantPrimitiveClass() { 75 ConstantBootstraps.nullConstant(MethodHandles.lookup(), null, int.class); 76 } 77 78 79 public void testPrimitiveClass() throws Throwable { 80 var pm = Map.of( 81 "I", int.class, 82 "J", long.class, 83 "S", short.class, 84 "B", byte.class, 85 "C", char.class, 86 "F", float.class, 87 "D", double.class, 88 "Z", boolean.class, 89 "V", void.class 90 ); 91 92 for (var desc : pm.keySet()) { 93 var handle = InstructionHelper.ldcDynamicConstant(L, desc, Class.class, 94 ConstantBootstraps.class, "primitiveClass", lookupMT(Class.class), 95 S -> {}); 96 assertEquals(handle.invoke(), pm.get(desc)); 97 } 98 } 99 100 @Test(expectedExceptions = NullPointerException.class) 101 public void testPrimitiveClassNullName() { 102 ConstantBootstraps.primitiveClass(MethodHandles.lookup(), null, Class.class); 103 } 104 105 @Test(expectedExceptions = NullPointerException.class) 106 public void testPrimitiveClassNullType() { 107 ConstantBootstraps.primitiveClass(MethodHandles.lookup(), "I", null); 108 } 109 110 @Test(expectedExceptions = IllegalArgumentException.class) 111 public void testPrimitiveClassEmptyName() { 112 ConstantBootstraps.primitiveClass(MethodHandles.lookup(), "", Class.class); 113 } 114 115 @Test(expectedExceptions = IllegalArgumentException.class) 116 public void testPrimitiveClassWrongNameChar() { 117 ConstantBootstraps.primitiveClass(MethodHandles.lookup(), "L", Class.class); 118 } 119 120 @Test(expectedExceptions = IllegalArgumentException.class) 121 public void testPrimitiveClassWrongNameString() { 122 ConstantBootstraps.primitiveClass(MethodHandles.lookup(), "Ljava/lang/Object;", Class.class); 123 } 124 125 126 public void testEnumConstant() throws Throwable { 127 for (var v : StackWalker.Option.values()) { 128 var handle = InstructionHelper.ldcDynamicConstant(L, v.name(), StackWalker.Option.class, 129 ConstantBootstraps.class, "enumConstant", lookupMT(Enum.class), 130 S -> { }); 131 assertEquals(handle.invoke(), v); 132 } 133 } 134 135 @Test(expectedExceptions = IllegalArgumentException.class) 136 public void testEnumConstantUnknown() { 137 ConstantBootstraps.enumConstant(MethodHandles.lookup(), "DOES_NOT_EXIST", StackWalker.Option.class); 138 } 139 140 141 public void testGetStaticDecl() throws Throwable { 142 var handle = InstructionHelper.ldcDynamicConstant(L, "TYPE", Class.class, 143 ConstantBootstraps.class, "getStaticFinal", lookupMT(Object.class, Class.class), 144 S -> { S.add("java/lang/Integer", PoolHelper::putClass); }); 145 assertEquals(handle.invoke(), int.class); 146 } 147 148 public void testGetStaticSelf() throws Throwable { 149 var handle = InstructionHelper.ldcDynamicConstant(L, "MAX_VALUE", int.class, 150 ConstantBootstraps.class, "getStaticFinal", lookupMT(Object.class), 151 S -> { }); 152 assertEquals(handle.invoke(), Integer.MAX_VALUE); 153 154 155 handle = InstructionHelper.ldcDynamicConstant(L, "ZERO", BigInteger.class, 156 ConstantBootstraps.class, "getStaticFinal", lookupMT(Object.class), 157 S -> { }); 158 assertEquals(handle.invoke(), BigInteger.ZERO); 159 } 160 161 162 public void testInvoke() throws Throwable { 163 var handle = InstructionHelper.ldcDynamicConstant( 164 L, "_", List.class, 165 ConstantBootstraps.class, "invoke", lookupMT(Object.class, MethodHandle.class, Object[].class), 166 S -> { 167 S.add("", (P, Z) -> { 168 return P.putHandle(MethodHandleInfo.REF_invokeStatic, "java/util/List", "of", 169 MethodType.methodType(List.class, Object[].class).toMethodDescriptorString(), 170 true); 171 }); 172 S.add(1).add(2).add(3).add(4); 173 }); 174 assertEquals(handle.invoke(), List.of(1, 2, 3, 4)); 175 } 176 177 public void testInvokeAsType() throws Throwable { 178 var handle = InstructionHelper.ldcDynamicConstant( 179 L, "_", int.class, 180 ConstantBootstraps.class, "invoke", lookupMT(Object.class, MethodHandle.class, Object[].class), 181 S -> { 182 S.add("", (P, Z) -> { 183 return P.putHandle(MethodHandleInfo.REF_invokeStatic, "java/lang/Integer", "valueOf", 184 MethodType.methodType(Integer.class, String.class).toMethodDescriptorString(), 185 false); 186 }); 187 S.add("42"); 188 }); 189 assertEquals(handle.invoke(), 42); 190 } 191 192 public void testInvokeAsTypeVariableArity() throws Throwable { 193 // The constant type is Collection but the invoke return type is List 194 var handle = InstructionHelper.ldcDynamicConstant( 195 L, "_", Collection.class, 196 ConstantBootstraps.class, "invoke", lookupMT(Object.class, MethodHandle.class, Object[].class), 197 S -> { 198 S.add("", (P, Z) -> { 199 return P.putHandle(MethodHandleInfo.REF_invokeStatic, "java/util/List", "of", 200 MethodType.methodType(List.class, Object[].class).toMethodDescriptorString(), 201 true); 202 }); 203 S.add(1).add(2).add(3).add(4); 204 }); 205 assertEquals(handle.invoke(), List.of(1, 2, 3, 4)); 206 } 207 208 @Test(expectedExceptions = ClassCastException.class) 209 public void testInvokeAsTypeClassCast() throws Throwable { 210 ConstantBootstraps.invoke(MethodHandles.lookup(), "_", String.class, 211 MethodHandles.lookup().findStatic(Integer.class, "valueOf", MethodType.methodType(Integer.class, String.class)), 212 "42"); 213 } 214 215 @Test(expectedExceptions = WrongMethodTypeException.class) 216 public void testInvokeAsTypeWrongReturnType() throws Throwable { 217 ConstantBootstraps.invoke(MethodHandles.lookup(), "_", short.class, 218 MethodHandles.lookup().findStatic(Integer.class, "parseInt", MethodType.methodType(int.class, String.class)), 219 "42"); 220 } 221 222 223 static class X { 224 public String f; 225 public static String sf; 226 } 227 228 public void testVarHandleField() throws Throwable { 229 var handle = InstructionHelper.ldcDynamicConstant( 230 L, "f", VarHandle.class, 231 ConstantBootstraps.class, "fieldVarHandle", lookupMT(VarHandle.class, Class.class, Class.class), 232 S -> { 233 S.add(X.class.getName().replace('.', '/'), PoolHelper::putClass). 234 add("java/lang/String", PoolHelper::putClass); 235 }); 236 237 var vhandle = (VarHandle) handle.invoke(); 238 assertEquals(vhandle.varType(), String.class); 239 assertEquals(vhandle.coordinateTypes(), List.of(X.class)); 240 } 241 242 public void testVarHandleStaticField() throws Throwable { 243 var handle = InstructionHelper.ldcDynamicConstant( 244 L, "sf", VarHandle.class, 245 ConstantBootstraps.class, "staticFieldVarHandle", lookupMT(VarHandle.class, Class.class, Class.class), 246 S -> { 247 S.add(X.class.getName().replace('.', '/'), PoolHelper::putClass). 248 add("java/lang/String", PoolHelper::putClass); 249 }); 250 251 var vhandle = (VarHandle) handle.invoke(); 252 assertEquals(vhandle.varType(), String.class); 253 assertEquals(vhandle.coordinateTypes(), List.of()); 254 } 255 256 public void testVarHandleArray() throws Throwable { 257 var handle = InstructionHelper.ldcDynamicConstant( 258 L, "_", VarHandle.class, 259 ConstantBootstraps.class, "arrayVarHandle", lookupMT(VarHandle.class, Class.class), 260 S -> { 261 S.add(String[].class.getName().replace('.', '/'), PoolHelper::putClass); 262 }); 263 264 var vhandle = (VarHandle) handle.invoke(); 265 assertEquals(vhandle.varType(), String.class); 266 assertEquals(vhandle.coordinateTypes(), List.of(String[].class, int.class)); 267 } 268 }