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