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