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