1 /* 2 * Copyright (c) 2009, 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 package test.java.lang.invoke; 25 26 import org.junit.*; 27 import test.java.lang.invoke.remote.RemoteExample; 28 29 import java.lang.invoke.MethodHandle; 30 import java.lang.invoke.MethodHandles; 31 import java.lang.invoke.MethodHandles.Lookup; 32 import java.lang.invoke.MethodType; 33 import java.lang.reflect.Array; 34 import java.lang.reflect.Field; 35 import java.lang.reflect.Modifier; 36 import java.util.ArrayList; 37 import java.util.Arrays; 38 import java.util.Collection; 39 import java.util.Collections; 40 import java.util.List; 41 42 import static org.junit.Assert.*; 43 44 /** 45 * 46 * @author jrose 47 */ 48 public abstract class MethodHandlesTest { 49 50 static final Class<?> THIS_CLASS = MethodHandlesTest.class; 51 // How much output? 52 static int verbosity = 0; 53 54 static { 55 String vstr = System.getProperty(THIS_CLASS.getSimpleName()+".verbosity"); 56 if (vstr == null) 57 vstr = System.getProperty(THIS_CLASS.getName()+".verbosity"); 58 if (vstr != null) verbosity = Integer.parseInt(vstr); 59 } 60 61 // Set this true during development if you want to fast-forward to 62 // a particular new, non-working test. Tests which are known to 63 // work (or have recently worked) test this flag and return on true. 64 static final boolean CAN_SKIP_WORKING; 65 66 static { 67 String vstr = System.getProperty(THIS_CLASS.getSimpleName()+".CAN_SKIP_WORKING"); 68 if (vstr == null) 69 vstr = System.getProperty(THIS_CLASS.getName()+".CAN_SKIP_WORKING"); 70 CAN_SKIP_WORKING = Boolean.parseBoolean(vstr); 71 } 72 73 // Set 'true' to do about 15x fewer tests, especially those redundant with RicochetTest. 74 // This might be useful with -Xcomp stress tests that compile all method handles. 75 static boolean CAN_TEST_LIGHTLY = Boolean.getBoolean(THIS_CLASS.getName()+".CAN_TEST_LIGHTLY"); 76 77 static final int MAX_ARG_INCREASE = 3; 78 79 String testName; 80 static int allPosTests, allNegTests; 81 int posTests, negTests; 82 83 @After printCounts()84 public void printCounts() { 85 if (verbosity >= 2 && (posTests | negTests) != 0) { 86 System.out.println(); 87 if (posTests != 0) System.out.println("=== "+testName+": "+posTests+" positive test cases run"); 88 if (negTests != 0) System.out.println("=== "+testName+": "+negTests+" negative test cases run"); 89 allPosTests += posTests; 90 allNegTests += negTests; 91 posTests = negTests = 0; 92 } 93 } 94 countTest(boolean positive)95 void countTest(boolean positive) { 96 if (positive) ++posTests; 97 else ++negTests; 98 } 99 countTest()100 void countTest() { countTest(true); } 101 startTest(String name)102 void startTest(String name) { 103 if (testName != null) printCounts(); 104 if (verbosity >= 1) 105 System.out.println(name); 106 posTests = negTests = 0; 107 testName = name; 108 } 109 110 @BeforeClass setUpClass()111 public static void setUpClass() throws Exception { 112 calledLog.clear(); 113 calledLog.add(null); 114 nextArgVal = INITIAL_ARG_VAL; 115 } 116 117 @AfterClass tearDownClass()118 public static void tearDownClass() throws Exception { 119 int posTests = allPosTests, negTests = allNegTests; 120 if (verbosity >= 0 && (posTests | negTests) != 0) { 121 System.out.println(); 122 if (posTests != 0) System.out.println("=== "+posTests+" total positive test cases"); 123 if (negTests != 0) System.out.println("=== "+negTests+" total negative test cases"); 124 } 125 } 126 127 static List<Object> calledLog = new ArrayList<>(); 128 logEntry(String name, Object... args)129 static Object logEntry(String name, Object... args) { 130 return Arrays.asList(name, Arrays.asList(args)); 131 } 132 called(String name, Object... args)133 public static Object called(String name, Object... args) { 134 Object entry = logEntry(name, args); 135 calledLog.add(entry); 136 return entry; 137 } 138 assertCalled(String name, Object... args)139 static void assertCalled(String name, Object... args) { 140 Object expected = logEntry(name, args); 141 Object actual = calledLog.get(calledLog.size() - 1); 142 if (expected.equals(actual) && verbosity < 9) return; 143 System.out.println("assertCalled "+name+":"); 144 System.out.println("expected: "+deepToString(expected)); 145 System.out.println("actual: "+actual); 146 System.out.println("ex. types: "+getClasses(expected)); 147 System.out.println("act. types: "+getClasses(actual)); 148 assertEquals("previous method call", expected, actual); 149 } 150 printCalled(MethodHandle target, String name, Object... args)151 static void printCalled(MethodHandle target, String name, Object... args) { 152 if (verbosity >= 3) 153 System.out.println("calling MH="+target+" to "+name+deepToString(args)); 154 } 155 deepToString(Object x)156 static String deepToString(Object x) { 157 if (x == null) return "null"; 158 if (x instanceof Collection) 159 x = ((Collection)x).toArray(); 160 if (x instanceof Object[]) { 161 Object[] ax = (Object[]) x; 162 ax = Arrays.copyOf(ax, ax.length, Object[].class); 163 for (int i = 0; i < ax.length; i++) 164 ax[i] = deepToString(ax[i]); 165 x = Arrays.deepToString(ax); 166 } 167 if (x.getClass().isArray()) 168 try { 169 x = Arrays.class.getMethod("toString", x.getClass()).invoke(null, x); 170 } catch (ReflectiveOperationException ex) { throw new Error(ex); } 171 assert(!(x instanceof Object[])); 172 return x.toString(); 173 } 174 castToWrapper(Object value, Class<?> dst)175 static Object castToWrapper(Object value, Class<?> dst) { 176 Object wrap = null; 177 if (value instanceof Number) 178 wrap = castToWrapperOrNull(((Number)value).longValue(), dst); 179 if (value instanceof Character) 180 wrap = castToWrapperOrNull((char)(Character)value, dst); 181 if (wrap != null) return wrap; 182 return dst.cast(value); 183 } 184 185 @SuppressWarnings("cast") // primitive cast to (long) is part of the pattern castToWrapperOrNull(long value, Class<?> dst)186 static Object castToWrapperOrNull(long value, Class<?> dst) { 187 if (dst == int.class || dst == Integer.class) 188 return (int)(value); 189 if (dst == long.class || dst == Long.class) 190 return (long)(value); 191 if (dst == char.class || dst == Character.class) 192 return (char)(value); 193 if (dst == short.class || dst == Short.class) 194 return (short)(value); 195 if (dst == float.class || dst == Float.class) 196 return (float)(value); 197 if (dst == double.class || dst == Double.class) 198 return (double)(value); 199 if (dst == byte.class || dst == Byte.class) 200 return (byte)(value); 201 if (dst == boolean.class || dst == boolean.class) 202 return ((value % 29) & 1) == 0; 203 return null; 204 } 205 206 static final int ONE_MILLION = (1000*1000), // first int value 207 TEN_BILLION = (10*1000*1000*1000), // scale factor to reach upper 32 bits 208 INITIAL_ARG_VAL = ONE_MILLION << 1; // <<1 makes space for sign bit; 209 static long nextArgVal; 210 nextArg(boolean moreBits)211 static long nextArg(boolean moreBits) { 212 long val = nextArgVal++; 213 long sign = -(val & 1); // alternate signs 214 val >>= 1; 215 if (moreBits) 216 // Guarantee some bits in the high word. 217 // In any case keep the decimal representation simple-looking, 218 // with lots of zeroes, so as not to make the printed decimal 219 // strings unnecessarily noisy. 220 val += (val % ONE_MILLION) * TEN_BILLION; 221 return val ^ sign; 222 } 223 nextArg()224 static int nextArg() { 225 // Produce a 32-bit result something like ONE_MILLION+(smallint). 226 // Example: 1_000_042. 227 return (int) nextArg(false); 228 } 229 nextArg(Class<?> kind)230 static long nextArg(Class<?> kind) { 231 if (kind == long.class || kind == Long.class || 232 kind == double.class || kind == Double.class) 233 // produce a 64-bit result something like 234 // ((TEN_BILLION+1) * (ONE_MILLION+(smallint))) 235 // Example: 10_000_420_001_000_042. 236 return nextArg(true); 237 return (long) nextArg(); 238 } 239 randomArg(Class<?> param)240 static Object randomArg(Class<?> param) { 241 Object wrap = castToWrapperOrNull(nextArg(param), param); 242 if (wrap != null) { 243 return wrap; 244 } 245 //import sun.invoke.util.Wrapper; 246 //Wrapper wrap = Wrapper.forBasicType(dst); 247 //if (wrap == Wrapper.OBJECT && Wrapper.isWrapperType(dst)) 248 // wrap = Wrapper.forWrapperType(dst); 249 // if (wrap != Wrapper.OBJECT) 250 // return wrap.wrap(nextArg++); 251 if (param.isInterface()) { 252 for (Class<?> c : param.getClasses()) { 253 if (param.isAssignableFrom(c) && !c.isInterface()) 254 { param = c; break; } 255 } 256 } 257 if (param.isArray()) { 258 Class<?> ctype = param.getComponentType(); 259 Object arg = Array.newInstance(ctype, 2); 260 Array.set(arg, 0, randomArg(ctype)); 261 return arg; 262 } 263 if (param.isInterface() && param.isAssignableFrom(List.class)) 264 return Arrays.asList("#"+nextArg()); 265 if (param.isInterface() || param.isAssignableFrom(String.class)) 266 return "#"+nextArg(); 267 else 268 try { 269 return param.newInstance(); 270 } catch (InstantiationException | IllegalAccessException ex) { 271 } 272 return null; // random class not Object, String, Integer, etc. 273 } 274 randomArgs(Class<?>.... params)275 static Object[] randomArgs(Class<?>... params) { 276 Object[] args = new Object[params.length]; 277 for (int i = 0; i < args.length; i++) 278 args[i] = randomArg(params[i]); 279 return args; 280 } 281 randomArgs(int nargs, Class<?> param)282 static Object[] randomArgs(int nargs, Class<?> param) { 283 Object[] args = new Object[nargs]; 284 for (int i = 0; i < args.length; i++) 285 args[i] = randomArg(param); 286 return args; 287 } 288 randomArgs(List<Class<?>> params)289 static Object[] randomArgs(List<Class<?>> params) { 290 return randomArgs(params.toArray(new Class<?>[params.size()])); 291 } 292 293 @SafeVarargs @SuppressWarnings("varargs") array(Class<T[]> atype, E... a)294 static <T, E extends T> T[] array(Class<T[]> atype, E... a) { 295 return Arrays.copyOf(a, a.length, atype); 296 } 297 298 @SafeVarargs @SuppressWarnings("varargs") cat(T[] a, T... b)299 static <T> T[] cat(T[] a, T... b) { 300 int alen = a.length, blen = b.length; 301 if (blen == 0) return a; 302 T[] c = Arrays.copyOf(a, alen + blen); 303 System.arraycopy(b, 0, c, alen, blen); 304 return c; 305 } 306 boxAll(int... vx)307 static Integer[] boxAll(int... vx) { 308 Integer[] res = new Integer[vx.length]; 309 for (int i = 0; i < res.length; i++) { 310 res[i] = vx[i]; 311 } 312 return res; 313 } 314 getClasses(Object x)315 static Object getClasses(Object x) { 316 if (x == null) return x; 317 if (x instanceof String) return x; // keep the name 318 if (x instanceof List) { 319 // recursively report classes of the list elements 320 Object[] xa = ((List)x).toArray(); 321 for (int i = 0; i < xa.length; i++) 322 xa[i] = getClasses(xa[i]); 323 return Arrays.asList(xa); 324 } 325 return x.getClass().getSimpleName(); 326 } 327 328 /** Return lambda(arg...[arity]) { new Object[]{ arg... } } */ varargsList(int arity)329 static MethodHandle varargsList(int arity) { 330 return ValueConversions.varargsList(arity); 331 } 332 333 /** Return lambda(arg...[arity]) { Arrays.asList(arg...) } */ varargsArray(int arity)334 static MethodHandle varargsArray(int arity) { 335 return ValueConversions.varargsArray(arity); 336 } 337 varargsArray(Class<?> arrayType, int arity)338 static MethodHandle varargsArray(Class<?> arrayType, int arity) { 339 return ValueConversions.varargsArray(arrayType, arity); 340 } 341 342 /** Variation of varargsList, but with the given rtype. */ varargsList(int arity, Class<?> rtype)343 static MethodHandle varargsList(int arity, Class<?> rtype) { 344 MethodHandle list = varargsList(arity); 345 MethodType listType = list.type().changeReturnType(rtype); 346 if (List.class.isAssignableFrom(rtype) || rtype == void.class || rtype == Object.class) { 347 // OK 348 } else if (rtype.isAssignableFrom(String.class)) { 349 if (LIST_TO_STRING == null) 350 try { 351 LIST_TO_STRING = PRIVATE.findStatic(PRIVATE.lookupClass(), "listToString", 352 MethodType.methodType(String.class, List.class)); 353 } catch (NoSuchMethodException | IllegalAccessException ex) { throw new RuntimeException(ex); } 354 list = MethodHandles.filterReturnValue(list, LIST_TO_STRING); 355 } else if (rtype.isPrimitive()) { 356 if (LIST_TO_INT == null) 357 try { 358 LIST_TO_INT = PRIVATE.findStatic(PRIVATE.lookupClass(), "listToInt", 359 MethodType.methodType(int.class, List.class)); 360 } catch (NoSuchMethodException | IllegalAccessException ex) { throw new RuntimeException(ex); } 361 list = MethodHandles.filterReturnValue(list, LIST_TO_INT); 362 list = MethodHandles.explicitCastArguments(list, listType); 363 } else { 364 throw new RuntimeException("varargsList: "+rtype); 365 } 366 return list.asType(listType); 367 } 368 369 /** Variation of varargsList, but with the given ptypes and rtype. */ varargsList(List<Class<?>> ptypes, Class<?> rtype)370 static MethodHandle varargsList(List<Class<?>> ptypes, Class<?> rtype) { 371 MethodHandle list = varargsList(ptypes.size(), rtype); 372 return list.asType(MethodType.methodType(rtype, ptypes)); 373 } 374 375 private static MethodHandle LIST_TO_STRING, LIST_TO_INT; listToString(List<?> x)376 private static String listToString(List<?> x) { return x.toString(); } listToInt(List<?> x)377 private static int listToInt(List<?> x) { return x.toString().hashCode(); } 378 changeArgTypes(MethodHandle target, Class<?> argType)379 static MethodHandle changeArgTypes(MethodHandle target, Class<?> argType) { 380 return changeArgTypes(target, 0, 999, argType); 381 } 382 changeArgTypes(MethodHandle target, int beg, int end, Class<?> argType)383 static MethodHandle changeArgTypes(MethodHandle target, 384 int beg, int end, Class<?> argType) { 385 MethodType targetType = target.type(); 386 end = Math.min(end, targetType.parameterCount()); 387 ArrayList<Class<?>> argTypes = new ArrayList<>(targetType.parameterList()); 388 Collections.fill(argTypes.subList(beg, end), argType); 389 MethodType ttype2 = MethodType.methodType(targetType.returnType(), argTypes); 390 return target.asType(ttype2); 391 } 392 addTrailingArgs(MethodHandle target, int nargs, Class<?> argClass)393 static MethodHandle addTrailingArgs(MethodHandle target, int nargs, Class<?> argClass) { 394 int targetLen = target.type().parameterCount(); 395 int extra = (nargs - targetLen); 396 if (extra <= 0) return target; 397 List<Class<?>> fakeArgs = Collections.<Class<?>>nCopies(extra, argClass); 398 return MethodHandles.dropArguments(target, targetLen, fakeArgs); 399 } 400 401 // This lookup is good for all members in and under MethodHandlesTest. 402 static final Lookup PRIVATE = MethodHandles.lookup(); 403 // This lookup is good for package-private members but not private ones. 404 static final Lookup PACKAGE = PackageSibling.lookup(); 405 // This lookup is good for public members and protected members of PubExample 406 static final Lookup SUBCLASS = RemoteExample.lookup(); 407 // This lookup is good only for public members in exported packages. 408 static final Lookup PUBLIC = MethodHandles.publicLookup(); 409 410 // Subject methods... 411 static class Example implements IntExample { 412 final String name; Example()413 public Example() { name = "Example#"+nextArg(); } Example(String name)414 protected Example(String name) { this.name = name; } 415 @SuppressWarnings("LeakingThisInConstructor") Example(int x)416 protected Example(int x) { this(); called("protected <init>", this, x); } 417 //Example(Void x) { does not exist; lookup elicts NoSuchMethodException } toString()418 @Override public String toString() { return name; } 419 v0()420 public void v0() { called("v0", this); } pro_v0()421 protected void pro_v0() { called("pro_v0", this); } pkg_v0()422 void pkg_v0() { called("pkg_v0", this); } pri_v0()423 private void pri_v0() { called("pri_v0", this); } s0()424 public static void s0() { called("s0"); } pro_s0()425 protected static void pro_s0() { called("pro_s0"); } pkg_s0()426 static void pkg_s0() { called("pkg_s0"); } pri_s0()427 private static void pri_s0() { called("pri_s0"); } 428 v1(Object x)429 public Object v1(Object x) { return called("v1", this, x); } v2(Object x, Object y)430 public Object v2(Object x, Object y) { return called("v2", this, x, y); } v2(Object x, int y)431 public Object v2(Object x, int y) { return called("v2", this, x, y); } v2(int x, Object y)432 public Object v2(int x, Object y) { return called("v2", this, x, y); } v2(int x, int y)433 public Object v2(int x, int y) { return called("v2", this, x, y); } s1(Object x)434 public static Object s1(Object x) { return called("s1", x); } s2(int x)435 public static Object s2(int x) { return called("s2", x); } s3(long x)436 public static Object s3(long x) { return called("s3", x); } s4(int x, int y)437 public static Object s4(int x, int y) { return called("s4", x, y); } s5(long x, int y)438 public static Object s5(long x, int y) { return called("s5", x, y); } s6(int x, long y)439 public static Object s6(int x, long y) { return called("s6", x, y); } s7(float x, double y)440 public static Object s7(float x, double y) { return called("s7", x, y); } 441 442 // for testing findConstructor: Example(String x, int y)443 public Example(String x, int y) { this.name = x+y; called("Example.<init>", x, y); } Example(int x, String y)444 public Example(int x, String y) { this.name = x+y; called("Example.<init>", x, y); } Example(int x, int y)445 public Example(int x, int y) { this.name = x+""+y; called("Example.<init>", x, y); } Example(int x, long y)446 public Example(int x, long y) { this.name = x+""+y; called("Example.<init>", x, y); } Example(int x, float y)447 public Example(int x, float y) { this.name = x+""+y; called("Example.<init>", x, y); } Example(int x, double y)448 public Example(int x, double y) { this.name = x+""+y; called("Example.<init>", x, y); } Example(int x, int y, int z)449 public Example(int x, int y, int z) { this.name = x+""+y+""+z; called("Example.<init>", x, y, z); } Example(int x, int y, int z, int a)450 public Example(int x, int y, int z, int a) { this.name = x+""+y+""+z+""+a; called("Example.<init>", x, y, z, a); } 451 452 static final Lookup EXAMPLE = MethodHandles.lookup(); // for testing findSpecial 453 } 454 455 static final Lookup EXAMPLE = Example.EXAMPLE; 456 public static class PubExample extends Example { PubExample()457 public PubExample() { this("PubExample"); } PubExample(String prefix)458 protected PubExample(String prefix) { super(prefix+"#"+nextArg()); } pro_v0()459 protected void pro_v0() { called("Pub/pro_v0", this); } pro_s0()460 protected static void pro_s0() { called("Pub/pro_s0"); } 461 } 462 463 static class SubExample extends Example { v0()464 @Override public void v0() { called("Sub/v0", this); } pkg_v0()465 @Override void pkg_v0() { called("Sub/pkg_v0", this); } 466 @SuppressWarnings("LeakingThisInConstructor") SubExample(int x)467 private SubExample(int x) { called("<init>", this, x); } SubExample()468 public SubExample() { super("SubExample#"+nextArg()); } 469 } 470 471 public static interface IntExample { v0()472 public void v0(); vd()473 public default void vd() { called("vd", this); } 474 public static class Impl implements IntExample { v0()475 public void v0() { called("Int/v0", this); } 476 final String name; Impl()477 public Impl() { name = "Impl#"+nextArg(); } toString()478 @Override public String toString() { return name; } 479 } 480 } 481 482 static interface SubIntExample extends IntExample { } 483 484 static final Object[][][] ACCESS_CASES = { 485 { { false, PUBLIC }, { false, SUBCLASS }, { false, PACKAGE }, { false, PRIVATE }, { false, EXAMPLE } }, //[0]: all false 486 { { false, PUBLIC }, { false, SUBCLASS }, { false, PACKAGE }, { true, PRIVATE }, { true, EXAMPLE } }, //[1]: only PRIVATE 487 { { false, PUBLIC }, { false, SUBCLASS }, { true, PACKAGE }, { true, PRIVATE }, { true, EXAMPLE } }, //[2]: PUBLIC false 488 { { false, PUBLIC }, { true, SUBCLASS }, { true, PACKAGE }, { true, PRIVATE }, { true, EXAMPLE } }, //[3]: subclass OK 489 { { true, PUBLIC }, { true, SUBCLASS }, { true, PACKAGE }, { true, PRIVATE }, { true, EXAMPLE } }, //[4]: all true 490 }; 491 accessCases(Class<?> defc, String name, boolean isSpecial)492 static Object[][] accessCases(Class<?> defc, String name, boolean isSpecial) { 493 Object[][] cases; 494 if (name.contains("pri_") || isSpecial) { 495 cases = ACCESS_CASES[1]; // PRIVATE only 496 } else if (name.contains("pkg_") || !Modifier.isPublic(defc.getModifiers())) { 497 cases = ACCESS_CASES[2]; // not PUBLIC 498 } else if (name.contains("pro_")) { 499 cases = ACCESS_CASES[3]; // PUBLIC class, protected member 500 } else { 501 assertTrue(name.indexOf('_') < 0 || name.contains("fin_")); 502 boolean pubc = Modifier.isPublic(defc.getModifiers()); 503 if (pubc) 504 cases = ACCESS_CASES[4]; // all access levels 505 else 506 cases = ACCESS_CASES[2]; // PACKAGE but not PUBLIC 507 } 508 if (defc != Example.class && cases[cases.length-1][1] == EXAMPLE) 509 cases = Arrays.copyOfRange(cases, 0, cases.length-1); 510 return cases; 511 } 512 513 static Object[][] accessCases(Class<?> defc, String name) { 514 return accessCases(defc, name, false); 515 } 516 517 static Lookup maybeMoveIn(Lookup lookup, Class<?> defc) { 518 if (lookup == PUBLIC || lookup == SUBCLASS || lookup == PACKAGE) 519 // external views stay external 520 return lookup; 521 return lookup.in(defc); 522 } 523 524 /** Is findVirtual (etc.) of "<init<" supposed to elicit a NoSuchMethodException? */ 525 static final boolean INIT_REF_CAUSES_NSME = true; 526 527 static void assertExceptionClass(Class<? extends Throwable> expected, 528 Throwable actual) { 529 if (expected.isInstance(actual)) return; 530 actual.printStackTrace(); 531 assertEquals(expected, actual.getClass()); 532 } 533 534 static final boolean DEBUG_METHOD_HANDLE_NAMES = Boolean.getBoolean("java.lang.invoke.MethodHandle.DEBUG_NAMES"); 535 536 // rough check of name string 537 static void assertNameStringContains(MethodHandle x, String s) { 538 if (!DEBUG_METHOD_HANDLE_NAMES) { 539 // ignore s 540 assertEquals("MethodHandle"+x.type(), x.toString()); 541 return; 542 } 543 if (x.toString().contains(s)) return; 544 assertEquals(s, x); 545 } 546 547 public static class HasFields { 548 boolean fZ = false; 549 byte fB = (byte)'B'; 550 short fS = (short)'S'; 551 char fC = 'C'; 552 int fI = 'I'; 553 long fJ = 'J'; 554 float fF = 'F'; 555 double fD = 'D'; 556 static boolean sZ = true; 557 static byte sB = 1+(byte)'B'; 558 static short sS = 1+(short)'S'; 559 static char sC = 1+'C'; 560 static int sI = 1+'I'; 561 static long sJ = 1+'J'; 562 static float sF = 1+'F'; 563 static double sD = 1+'D'; 564 565 Object fL = 'L'; 566 String fR = "R"; 567 static Object sL = 'M'; 568 static String sR = "S"; 569 570 static final Object[][] CASES; 571 static { 572 ArrayList<Object[]> cases = new ArrayList<>(); 573 Object types[][] = { 574 {'L',Object.class}, {'R',String.class}, 575 {'I',int.class}, {'J',long.class}, 576 {'F',float.class}, {'D',double.class}, 577 {'Z',boolean.class}, {'B',byte.class}, 578 {'S',short.class}, {'C',char.class}, 579 }; 580 HasFields fields = new HasFields(); 581 for (Object[] t : types) { 582 for (int kind = 0; kind <= 1; kind++) { 583 boolean isStatic = (kind != 0); 584 char btc = (Character)t[0]; 585 String name = (isStatic ? "s" : "f") + btc; 586 Class<?> type = (Class<?>) t[1]; 587 Object value; 588 Field field; 589 try { 590 field = HasFields.class.getDeclaredField(name); 591 } catch (NoSuchFieldException | SecurityException ex) { 592 throw new InternalError("no field HasFields."+name); 593 } 594 try { 595 value = field.get(fields); 596 } catch (IllegalArgumentException | IllegalAccessException ex) { 597 throw new InternalError("cannot fetch field HasFields."+name); 598 } 599 if (type == float.class) { 600 float v = 'F'; 601 if (isStatic) v++; 602 assertTrue(value.equals(v)); 603 } 604 assertTrue(name.equals(field.getName())); 605 assertTrue(type.equals(field.getType())); 606 assertTrue(isStatic == (Modifier.isStatic(field.getModifiers()))); 607 cases.add(new Object[]{ field, value }); 608 } 609 } 610 cases.add(new Object[]{ new Object[]{ false, HasFields.class, "bogus_fD", double.class }, Error.class }); 611 cases.add(new Object[]{ new Object[]{ true, HasFields.class, "bogus_sL", Object.class }, Error.class }); 612 CASES = cases.toArray(new Object[0][]); 613 } 614 } 615 616 static final int TEST_UNREFLECT = 1, TEST_FIND_FIELD = 2, TEST_FIND_STATIC = 3, TEST_SETTER = 0x10, TEST_BOUND = 0x20, TEST_NPE = 0x40; 617 618 static boolean testModeMatches(int testMode, boolean isStatic) { 619 switch (testMode) { 620 case TEST_FIND_STATIC: return isStatic; 621 case TEST_FIND_FIELD: return !isStatic; 622 case TEST_UNREFLECT: return true; // unreflect matches both 623 } 624 throw new InternalError("testMode="+testMode); 625 } 626 627 static class Callee { 628 static Object id() { return called("id"); } 629 static Object id(Object x) { return called("id", x); } 630 static Object id(Object x, Object y) { return called("id", x, y); } 631 static Object id(Object x, Object y, Object z) { return called("id", x, y, z); } 632 static Object id(Object... vx) { return called("id", vx); } 633 static MethodHandle ofType(int n) { 634 return ofType(Object.class, n); 635 } 636 static MethodHandle ofType(Class<?> rtype, int n) { 637 if (n == -1) 638 return ofType(MethodType.methodType(rtype, Object[].class)); 639 return ofType(MethodType.genericMethodType(n).changeReturnType(rtype)); 640 } 641 static MethodHandle ofType(Class<?> rtype, Class<?>... ptypes) { 642 return ofType(MethodType.methodType(rtype, ptypes)); 643 } 644 static MethodHandle ofType(MethodType type) { 645 Class<?> rtype = type.returnType(); 646 String pfx = ""; 647 if (rtype != Object.class) 648 pfx = rtype.getSimpleName().substring(0, 1).toLowerCase(); 649 String name = pfx+"id"; 650 try { 651 return PRIVATE.findStatic(Callee.class, name, type); 652 } catch (NoSuchMethodException | IllegalAccessException ex) { 653 throw new RuntimeException(ex); 654 } 655 } 656 } 657 658 static Object invokee(Object... args) { 659 return called("invokee", args).hashCode(); 660 } 661 662 protected static final String MISSING_ARG = "missingArg"; 663 protected static final String MISSING_ARG_2 = "missingArg#2"; 664 665 static Object targetIfEquals() { 666 return called("targetIfEquals"); 667 } 668 669 static Object fallbackIfNotEquals() { 670 return called("fallbackIfNotEquals"); 671 } 672 673 static Object targetIfEquals(Object x) { 674 assertEquals(x, MISSING_ARG); 675 return called("targetIfEquals", x); 676 } 677 678 static Object fallbackIfNotEquals(Object x) { 679 assertFalse(x.toString(), x.equals(MISSING_ARG)); 680 return called("fallbackIfNotEquals", x); 681 } 682 683 static Object targetIfEquals(Object x, Object y) { 684 assertEquals(x, y); 685 return called("targetIfEquals", x, y); 686 } 687 688 static Object fallbackIfNotEquals(Object x, Object y) { 689 assertFalse(x.toString(), x.equals(y)); 690 return called("fallbackIfNotEquals", x, y); 691 } 692 693 static Object targetIfEquals(Object x, Object y, Object z) { 694 assertEquals(x, y); 695 return called("targetIfEquals", x, y, z); 696 } 697 698 static Object fallbackIfNotEquals(Object x, Object y, Object z) { 699 assertFalse(x.toString(), x.equals(y)); 700 return called("fallbackIfNotEquals", x, y, z); 701 } 702 703 static boolean loopIntPred(int a) { 704 if (verbosity >= 5) { 705 System.out.println("int pred " + a + " -> " + (a < 7)); 706 } 707 return a < 7; 708 } 709 710 static boolean loopDoublePred(int a, double b) { 711 if (verbosity >= 5) { 712 System.out.println("double pred (a=" + a + ") " + b + " -> " + (b > 0.5)); 713 } 714 return b > 0.5; 715 } 716 loopStringPred(int a, double b, String c)717 static boolean loopStringPred(int a, double b, String c) { 718 if (verbosity >= 5) { 719 System.out.println("String pred (a=" + a + ",b=" + b + ") " + c + " -> " + (c.length() <= 9)); 720 } 721 return c.length() <= 9; 722 } 723 loopIntStep(int a)724 static int loopIntStep(int a) { 725 if (verbosity >= 5) { 726 System.out.println("int step " + a + " -> " + (a + 1)); 727 } 728 return a + 1; 729 } 730 loopDoubleStep(int a, double b)731 static double loopDoubleStep(int a, double b) { 732 if (verbosity >= 5) { 733 System.out.println("double step (a=" + a + ") " + b + " -> " + (b / 2.0)); 734 } 735 return b / 2.0; 736 } 737 loopStringStep(int a, double b, String c)738 static String loopStringStep(int a, double b, String c) { 739 if (verbosity >= 5) { 740 System.out.println("String step (a=" + a + ",b=" + b + ") " + c + " -> " + (c + a)); 741 } 742 return c + a; 743 } 744 vtarget(String[] a)745 static void vtarget(String[] a) { 746 // naught, akin to identity 747 } 748 vtargetThrow(String[] a)749 static void vtargetThrow(String[] a) throws Exception { 750 throw new Exception("thrown"); 751 } 752 vcleanupPassThrough(Throwable t, String[] a)753 static void vcleanupPassThrough(Throwable t, String[] a) { 754 assertNull(t); 755 // naught, akin to identity 756 } 757 vcleanupAugment(Throwable t, String[] a)758 static void vcleanupAugment(Throwable t, String[] a) { 759 assertNull(t); 760 a[0] = "augmented"; 761 } 762 vcleanupCatch(Throwable t, String[] a)763 static void vcleanupCatch(Throwable t, String[] a) { 764 assertNotNull(t); 765 a[0] = "caught"; 766 } 767 vcleanupThrow(Throwable t, String[] a)768 static void vcleanupThrow(Throwable t, String[] a) throws Exception { 769 assertNotNull(t); 770 throw new Exception("rethrown"); 771 } 772 } 773 // Local abbreviated copy of sun.invoke.util.ValueConversions 774 // This guy tests access from outside the same package member, but inside 775 // the package itself. 776 class ValueConversions { 777 private static final Lookup IMPL_LOOKUP = MethodHandles.lookup(); 778 private static final Object[] NO_ARGS_ARRAY = {}; makeArray(Object... args)779 private static Object[] makeArray(Object... args) { return args; } array()780 private static Object[] array() { return NO_ARGS_ARRAY; } array(Object a0)781 private static Object[] array(Object a0) 782 { return makeArray(a0); } array(Object a0, Object a1)783 private static Object[] array(Object a0, Object a1) 784 { return makeArray(a0, a1); } array(Object a0, Object a1, Object a2)785 private static Object[] array(Object a0, Object a1, Object a2) 786 { return makeArray(a0, a1, a2); } array(Object a0, Object a1, Object a2, Object a3)787 private static Object[] array(Object a0, Object a1, Object a2, Object a3) 788 { return makeArray(a0, a1, a2, a3); } array(Object a0, Object a1, Object a2, Object a3, Object a4)789 private static Object[] array(Object a0, Object a1, Object a2, Object a3, 790 Object a4) 791 { return makeArray(a0, a1, a2, a3, a4); } array(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5)792 private static Object[] array(Object a0, Object a1, Object a2, Object a3, 793 Object a4, Object a5) 794 { return makeArray(a0, a1, a2, a3, a4, a5); } array(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6)795 private static Object[] array(Object a0, Object a1, Object a2, Object a3, 796 Object a4, Object a5, Object a6) 797 { return makeArray(a0, a1, a2, a3, a4, a5, a6); } array(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7)798 private static Object[] array(Object a0, Object a1, Object a2, Object a3, 799 Object a4, Object a5, Object a6, Object a7) 800 { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7); } array(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8)801 private static Object[] array(Object a0, Object a1, Object a2, Object a3, 802 Object a4, Object a5, Object a6, Object a7, 803 Object a8) 804 { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8); } array(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9)805 private static Object[] array(Object a0, Object a1, Object a2, Object a3, 806 Object a4, Object a5, Object a6, Object a7, 807 Object a8, Object a9) 808 { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } 809 makeArrays()810 static MethodHandle[] makeArrays() { 811 ArrayList<MethodHandle> arrays = new ArrayList<>(); 812 MethodHandles.Lookup lookup = IMPL_LOOKUP; 813 for (;;) { 814 int nargs = arrays.size(); 815 MethodType type = MethodType.genericMethodType(nargs).changeReturnType(Object[].class); 816 String name = "array"; 817 MethodHandle array = null; 818 try { 819 array = lookup.findStatic(ValueConversions.class, name, type); 820 } catch (ReflectiveOperationException ex) { 821 // break from loop! 822 } 823 if (array == null) break; 824 arrays.add(array); 825 } 826 assertTrue(arrays.size() == 11); // current number of methods 827 return arrays.toArray(new MethodHandle[0]); 828 } 829 830 static final MethodHandle[] ARRAYS = makeArrays(); 831 832 /** Return a method handle that takes the indicated number of Object 833 * arguments and returns an Object array of them, as if for varargs. 834 */ varargsArray(int nargs)835 public static MethodHandle varargsArray(int nargs) { 836 if (nargs < ARRAYS.length) 837 return ARRAYS[nargs]; 838 return MethodHandles.identity(Object[].class).asCollector(Object[].class, nargs); 839 } 840 varargsArray(Class<?> arrayType, int nargs)841 public static MethodHandle varargsArray(Class<?> arrayType, int nargs) { 842 Class<?> elemType = arrayType.getComponentType(); 843 MethodType vaType = MethodType.methodType(arrayType, Collections.<Class<?>>nCopies(nargs, elemType)); 844 MethodHandle mh = varargsArray(nargs); 845 if (arrayType != Object[].class) 846 mh = MethodHandles.filterReturnValue(mh, CHANGE_ARRAY_TYPE.bindTo(arrayType)); 847 return mh.asType(vaType); 848 } 849 changeArrayType(Class<?> arrayType, Object[] a)850 static Object changeArrayType(Class<?> arrayType, Object[] a) { 851 Class<?> elemType = arrayType.getComponentType(); 852 if (!elemType.isPrimitive()) 853 return Arrays.copyOf(a, a.length, arrayType.asSubclass(Object[].class)); 854 Object b = java.lang.reflect.Array.newInstance(elemType, a.length); 855 for (int i = 0; i < a.length; i++) 856 java.lang.reflect.Array.set(b, i, a[i]); 857 return b; 858 } 859 860 private static final MethodHandle CHANGE_ARRAY_TYPE; 861 static { 862 try { 863 CHANGE_ARRAY_TYPE = IMPL_LOOKUP.findStatic(ValueConversions.class, "changeArrayType", 864 MethodType.methodType(Object.class, Class.class, Object[].class)); 865 } catch (NoSuchMethodException | IllegalAccessException ex) { 866 Error err = new InternalError("uncaught exception"); 867 err.initCause(ex); 868 throw err; 869 } 870 } 871 872 private static final List<Object> NO_ARGS_LIST = Arrays.asList(NO_ARGS_ARRAY); makeList(Object... args)873 private static List<Object> makeList(Object... args) { return Arrays.asList(args); } list()874 private static List<Object> list() { return NO_ARGS_LIST; } list(Object a0)875 private static List<Object> list(Object a0) 876 { return makeList(a0); } list(Object a0, Object a1)877 private static List<Object> list(Object a0, Object a1) 878 { return makeList(a0, a1); } list(Object a0, Object a1, Object a2)879 private static List<Object> list(Object a0, Object a1, Object a2) 880 { return makeList(a0, a1, a2); } list(Object a0, Object a1, Object a2, Object a3)881 private static List<Object> list(Object a0, Object a1, Object a2, Object a3) 882 { return makeList(a0, a1, a2, a3); } list(Object a0, Object a1, Object a2, Object a3, Object a4)883 private static List<Object> list(Object a0, Object a1, Object a2, Object a3, 884 Object a4) 885 { return makeList(a0, a1, a2, a3, a4); } list(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5)886 private static List<Object> list(Object a0, Object a1, Object a2, Object a3, 887 Object a4, Object a5) 888 { return makeList(a0, a1, a2, a3, a4, a5); } list(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6)889 private static List<Object> list(Object a0, Object a1, Object a2, Object a3, 890 Object a4, Object a5, Object a6) 891 { return makeList(a0, a1, a2, a3, a4, a5, a6); } list(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7)892 private static List<Object> list(Object a0, Object a1, Object a2, Object a3, 893 Object a4, Object a5, Object a6, Object a7) 894 { return makeList(a0, a1, a2, a3, a4, a5, a6, a7); } list(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8)895 private static List<Object> list(Object a0, Object a1, Object a2, Object a3, 896 Object a4, Object a5, Object a6, Object a7, 897 Object a8) 898 { return makeList(a0, a1, a2, a3, a4, a5, a6, a7, a8); } list(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9)899 private static List<Object> list(Object a0, Object a1, Object a2, Object a3, 900 Object a4, Object a5, Object a6, Object a7, 901 Object a8, Object a9) 902 { return makeList(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } 903 makeLists()904 static MethodHandle[] makeLists() { 905 ArrayList<MethodHandle> lists = new ArrayList<>(); 906 MethodHandles.Lookup lookup = IMPL_LOOKUP; 907 for (;;) { 908 int nargs = lists.size(); 909 MethodType type = MethodType.genericMethodType(nargs).changeReturnType(List.class); 910 String name = "list"; 911 MethodHandle list = null; 912 try { 913 list = lookup.findStatic(ValueConversions.class, name, type); 914 } catch (ReflectiveOperationException ex) { 915 // break from loop! 916 } 917 if (list == null) break; 918 lists.add(list); 919 } 920 assertTrue(lists.size() == 11); // current number of methods 921 return lists.toArray(new MethodHandle[0]); 922 } 923 924 static final MethodHandle[] LISTS = makeLists(); 925 static final MethodHandle AS_LIST; 926 927 static { 928 try { 929 AS_LIST = IMPL_LOOKUP.findStatic(Arrays.class, "asList", MethodType.methodType(List.class, Object[].class)); 930 } catch (NoSuchMethodException | IllegalAccessException ex) { throw new RuntimeException(ex); } 931 } 932 933 /** Return a method handle that takes the indicated number of Object 934 * arguments and returns List. 935 */ varargsList(int nargs)936 public static MethodHandle varargsList(int nargs) { 937 if (nargs < LISTS.length) 938 return LISTS[nargs]; 939 return AS_LIST.asCollector(Object[].class, nargs); 940 } 941 } 942 // This guy tests access from outside the same package member, but inside 943 // the package itself. 944 class PackageSibling { lookup()945 static Lookup lookup() { 946 return MethodHandles.lookup(); 947 } 948 } 949