1 /* 2 * Copyright (c) 2013, 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 7087570 27 * @summary REF_invokeSpecial DMHs (which are unusual) get marked explicitly; tweak the MHI to use this bit 28 * 29 * @run main Test7087570 30 */ 31 32 import java.lang.invoke.*; 33 import java.lang.reflect.*; 34 import java.util.*; 35 36 import static java.lang.invoke.MethodHandles.*; 37 import static java.lang.invoke.MethodType.*; 38 import static java.lang.invoke.MethodHandleInfo.*; 39 40 public class Test7087570 { 41 42 private static final TestMethodData[] TESTS = new TestMethodData[] { 43 // field accessors 44 data(DummyFieldHolder.class, "instanceField", getterMethodType(String.class), DummyFieldHolder.class, REF_getField), 45 data(DummyFieldHolder.class, "instanceField", setterMethodType(String.class), DummyFieldHolder.class, REF_putField), 46 data(DummyFieldHolder.class, "staticField", getterMethodType(Integer.class), DummyFieldHolder.class, REF_getStatic), 47 data(DummyFieldHolder.class, "staticField", setterMethodType(Integer.class), DummyFieldHolder.class, REF_putStatic), 48 data(DummyFieldHolder.class, "instanceByteField", getterMethodType(byte.class), DummyFieldHolder.class, REF_getField), 49 data(DummyFieldHolder.class, "instanceByteField", setterMethodType(byte.class), DummyFieldHolder.class, REF_putField), 50 51 // REF_invokeVirtual 52 data(Object.class, "hashCode", methodType(int.class), Object.class, REF_invokeVirtual), 53 54 // REF_invokeVirtual strength-reduced to REF_invokeSpecial, 55 // test if it normalizes back to REF_invokeVirtual in MethodHandleInfo as expected 56 data(String.class, "hashCode", methodType(int.class), String.class, REF_invokeVirtual), 57 58 // REF_invokeStatic 59 data(Collections.class, "sort", methodType(void.class, List.class), Collections.class, REF_invokeStatic), 60 data(Arrays.class, "asList", methodType(List.class, Object[].class), Arrays.class, REF_invokeStatic), // varargs case 61 62 // REF_invokeSpecial 63 data(Object.class, "hashCode", methodType(int.class), Object.class, REF_invokeSpecial), 64 65 // REF_newInvokeSpecial 66 data(String.class, "<init>", methodType(void.class, char[].class), String.class, REF_newInvokeSpecial), 67 data(DummyFieldHolder.class, "<init>", methodType(void.class, byte.class, Long[].class), DummyFieldHolder.class, REF_newInvokeSpecial), // varargs case 68 69 // REF_invokeInterface 70 data(List.class, "size", methodType(int.class), List.class, REF_invokeInterface) 71 }; 72 73 public static void main(String... args) throws Throwable { 74 testWithLookup(); 75 testWithUnreflect(); 76 } 77 78 private static void doTest(MethodHandle mh, TestMethodData testMethod) { 79 MethodHandleInfo mhi = LOOKUP.revealDirect(mh); 80 81 System.out.printf("%s.%s: %s, nominal refKind: %s, actual refKind: %s\n", 82 testMethod.clazz.getName(), testMethod.name, testMethod.methodType, 83 referenceKindToString(testMethod.referenceKind), 84 referenceKindToString(mhi.getReferenceKind())); 85 assertEquals(testMethod.name, mhi.getName()); 86 assertEquals(testMethod.methodType, mhi.getMethodType()); 87 assertEquals(testMethod.declaringClass, mhi.getDeclaringClass()); 88 assertEquals(testMethod.referenceKind == REF_invokeSpecial, isInvokeSpecial(mh)); 89 assertRefKindEquals(testMethod.referenceKind, mhi.getReferenceKind()); 90 } 91 92 private static void testWithLookup() throws Throwable { 93 for (TestMethodData testMethod : TESTS) { 94 MethodHandle mh = lookupFrom(testMethod); 95 doTest(mh, testMethod); 96 } 97 } 98 99 private static void testWithUnreflect() throws Throwable { 100 for (TestMethodData testMethod : TESTS) { 101 MethodHandle mh = unreflectFrom(testMethod); 102 doTest(mh, testMethod); 103 } 104 } 105 106 private static MethodType getterMethodType(Class<?> clazz) { 107 return methodType(clazz); 108 } 109 110 private static MethodType setterMethodType(Class<?> clazz) { 111 return methodType(void.class, clazz); 112 } 113 114 private static final Lookup LOOKUP = lookup(); 115 116 private static class TestMethodData { 117 final Class<?> clazz; 118 final String name; 119 final MethodType methodType; 120 final Class<?> declaringClass; 121 final int referenceKind; // the nominal refKind 122 123 public TestMethodData(Class<?> clazz, String name, 124 MethodType methodType, Class<?> declaringClass, 125 int referenceKind) { 126 this.clazz = clazz; 127 this.name = name; 128 this.methodType = methodType; 129 this.declaringClass = declaringClass; 130 this.referenceKind = referenceKind; 131 } 132 } 133 134 private static TestMethodData data(Class<?> clazz, String name, 135 MethodType methodType, Class<?> declaringClass, 136 int referenceKind) { 137 return new TestMethodData(clazz, name, methodType, declaringClass, referenceKind); 138 } 139 140 private static MethodHandle lookupFrom(TestMethodData testMethod) 141 throws NoSuchMethodException, NoSuchFieldException, IllegalAccessException { 142 switch (testMethod.referenceKind) { 143 case REF_getField: 144 return LOOKUP.findGetter(testMethod.clazz, testMethod.name, testMethod.methodType.returnType()); 145 case REF_putField: 146 return LOOKUP.findSetter(testMethod.clazz, testMethod.name, testMethod.methodType.parameterType(0)); 147 case REF_getStatic: 148 return LOOKUP.findStaticGetter(testMethod.clazz, testMethod.name, testMethod.methodType.returnType()); 149 case REF_putStatic: 150 return LOOKUP.findStaticSetter(testMethod.clazz, testMethod.name, testMethod.methodType.parameterType(0)); 151 case REF_invokeVirtual: 152 case REF_invokeInterface: 153 return LOOKUP.findVirtual(testMethod.clazz, testMethod.name, testMethod.methodType); 154 case REF_invokeStatic: 155 return LOOKUP.findStatic(testMethod.clazz, testMethod.name, testMethod.methodType); 156 case REF_invokeSpecial: 157 Class<?> thisClass = LOOKUP.lookupClass(); 158 MethodHandle smh = LOOKUP.findSpecial(testMethod.clazz, testMethod.name, testMethod.methodType, thisClass); 159 noteInvokeSpecial(smh); 160 return smh; 161 case REF_newInvokeSpecial: 162 return LOOKUP.findConstructor(testMethod.clazz, testMethod.methodType); 163 default: 164 throw new Error("ERROR: unexpected referenceKind in test data"); 165 } 166 } 167 168 private static MethodHandle unreflectFrom(TestMethodData testMethod) 169 throws NoSuchMethodException, NoSuchFieldException, IllegalAccessException { 170 switch (testMethod.referenceKind) { 171 case REF_getField: 172 case REF_getStatic: { 173 Field f = testMethod.clazz.getDeclaredField(testMethod.name); 174 return LOOKUP.unreflectGetter(f); 175 } 176 case REF_putField: 177 case REF_putStatic: { 178 Field f = testMethod.clazz.getDeclaredField(testMethod.name); 179 return LOOKUP.unreflectSetter(f); 180 } 181 case REF_invokeVirtual: 182 case REF_invokeStatic: 183 case REF_invokeInterface: { 184 Method m = testMethod.clazz.getDeclaredMethod(testMethod.name, testMethod.methodType.parameterArray()); 185 return LOOKUP.unreflect(m); 186 } 187 case REF_invokeSpecial: { 188 Method m = testMethod.clazz.getDeclaredMethod(testMethod.name, testMethod.methodType.parameterArray()); 189 Class<?> thisClass = LOOKUP.lookupClass(); 190 MethodHandle smh = LOOKUP.unreflectSpecial(m, thisClass); 191 noteInvokeSpecial(smh); 192 return smh; 193 } 194 case REF_newInvokeSpecial: { 195 Constructor c = testMethod.clazz.getDeclaredConstructor(testMethod.methodType.parameterArray()); 196 return LOOKUP.unreflectConstructor(c); 197 } 198 default: 199 throw new Error("ERROR: unexpected referenceKind in test data"); 200 } 201 } 202 203 private static List<MethodHandle> specialMethodHandles = new ArrayList<>(); 204 private static void noteInvokeSpecial(MethodHandle mh) { 205 specialMethodHandles.add(mh); 206 assert(isInvokeSpecial(mh)); 207 } 208 private static boolean isInvokeSpecial(MethodHandle mh) { 209 return specialMethodHandles.contains(mh); 210 } 211 212 private static void assertRefKindEquals(int expect, int observed) { 213 if (expect == observed) return; 214 215 String msg = "expected " + referenceKindToString(expect) + 216 " but observed " + referenceKindToString(observed); 217 System.out.println("FAILED: " + msg); 218 throw new AssertionError(msg); 219 } 220 221 private static void assertEquals(Object expect, Object observed) { 222 if (java.util.Objects.equals(expect, observed)) return; 223 224 String msg = "expected " + expect + " but observed " + observed; 225 System.out.println("FAILED: " + msg); 226 throw new AssertionError(msg); 227 } 228 } 229 230 class DummyFieldHolder { 231 public static Integer staticField; 232 public String instanceField; 233 public byte instanceByteField; 234 235 public DummyFieldHolder(byte unused1, Long... unused2) { 236 } 237 } 238