Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/test/java/lang/invoke/MethodHandlesTest.java
47209 views
/*1* Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/* @test24* @summary unit tests for java.lang.invoke.MethodHandles25* @library /lib/testlibrary /lib/testlibrary/jsr29226* @compile MethodHandlesTest.java remote/RemoteExample.java27* @run junit/othervm/timeout=2500 -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies -esa test.java.lang.invoke.MethodHandlesTest28*/2930package test.java.lang.invoke;3132import test.java.lang.invoke.remote.RemoteExample;33import java.lang.invoke.*;34import java.lang.invoke.MethodHandles.Lookup;35import java.lang.reflect.*;36import java.util.*;37import org.junit.*;38import static org.junit.Assert.*;39import com.oracle.testlibrary.jsr292.CodeCacheOverflowProcessor;404142/**43*44* @author jrose45*/46public class MethodHandlesTest {47static final Class<?> THIS_CLASS = MethodHandlesTest.class;48// How much output?49static int verbosity = 0;50static {51String vstr = System.getProperty(THIS_CLASS.getSimpleName()+".verbosity");52if (vstr == null)53vstr = System.getProperty(THIS_CLASS.getName()+".verbosity");54if (vstr != null) verbosity = Integer.parseInt(vstr);55}5657// Set this true during development if you want to fast-forward to58// a particular new, non-working test. Tests which are known to59// work (or have recently worked) test this flag and return on true.60static final boolean CAN_SKIP_WORKING;61static {62String vstr = System.getProperty(THIS_CLASS.getSimpleName()+".CAN_SKIP_WORKING");63if (vstr == null)64vstr = System.getProperty(THIS_CLASS.getName()+".CAN_SKIP_WORKING");65CAN_SKIP_WORKING = Boolean.parseBoolean(vstr);66}6768// Set 'true' to do about 15x fewer tests, especially those redundant with RicochetTest.69// This might be useful with -Xcomp stress tests that compile all method handles.70static boolean CAN_TEST_LIGHTLY = Boolean.getBoolean(THIS_CLASS.getName()+".CAN_TEST_LIGHTLY");7172@Test73public void testFirst() throws Throwable {74verbosity += 9; try {75// left blank for debugging76} finally { printCounts(); verbosity -= 9; }77}7879static final int MAX_ARG_INCREASE = 3;8081public MethodHandlesTest() {82}8384String testName;85static int allPosTests, allNegTests;86int posTests, negTests;87@After88public void printCounts() {89if (verbosity >= 2 && (posTests | negTests) != 0) {90System.out.println();91if (posTests != 0) System.out.println("=== "+testName+": "+posTests+" positive test cases run");92if (negTests != 0) System.out.println("=== "+testName+": "+negTests+" negative test cases run");93allPosTests += posTests;94allNegTests += negTests;95posTests = negTests = 0;96}97}98void countTest(boolean positive) {99if (positive) ++posTests;100else ++negTests;101}102void countTest() { countTest(true); }103void startTest(String name) {104if (testName != null) printCounts();105if (verbosity >= 1)106System.out.println(name);107posTests = negTests = 0;108testName = name;109}110111@BeforeClass112public static void setUpClass() throws Exception {113calledLog.clear();114calledLog.add(null);115nextArgVal = INITIAL_ARG_VAL;116}117118@AfterClass119public static void tearDownClass() throws Exception {120int posTests = allPosTests, negTests = allNegTests;121if (verbosity >= 0 && (posTests | negTests) != 0) {122System.out.println();123if (posTests != 0) System.out.println("=== "+posTests+" total positive test cases");124if (negTests != 0) System.out.println("=== "+negTests+" total negative test cases");125}126}127128static List<Object> calledLog = new ArrayList<>();129static Object logEntry(String name, Object... args) {130return Arrays.asList(name, Arrays.asList(args));131}132public static Object called(String name, Object... args) {133Object entry = logEntry(name, args);134calledLog.add(entry);135return entry;136}137static void assertCalled(String name, Object... args) {138Object expected = logEntry(name, args);139Object actual = calledLog.get(calledLog.size() - 1);140if (expected.equals(actual) && verbosity < 9) return;141System.out.println("assertCalled "+name+":");142System.out.println("expected: "+deepToString(expected));143System.out.println("actual: "+actual);144System.out.println("ex. types: "+getClasses(expected));145System.out.println("act. types: "+getClasses(actual));146assertEquals("previous method call", expected, actual);147}148static void printCalled(MethodHandle target, String name, Object... args) {149if (verbosity >= 3)150System.out.println("calling MH="+target+" to "+name+deepToString(args));151}152static String deepToString(Object x) {153if (x == null) return "null";154if (x instanceof Collection)155x = ((Collection)x).toArray();156if (x instanceof Object[]) {157Object[] ax = (Object[]) x;158ax = Arrays.copyOf(ax, ax.length, Object[].class);159for (int i = 0; i < ax.length; i++)160ax[i] = deepToString(ax[i]);161x = Arrays.deepToString(ax);162}163if (x.getClass().isArray())164try {165x = Arrays.class.getMethod("toString", x.getClass()).invoke(null, x);166} catch (ReflectiveOperationException ex) { throw new Error(ex); }167assert(!(x instanceof Object[]));168return x.toString();169}170171static Object castToWrapper(Object value, Class<?> dst) {172Object wrap = null;173if (value instanceof Number)174wrap = castToWrapperOrNull(((Number)value).longValue(), dst);175if (value instanceof Character)176wrap = castToWrapperOrNull((char)(Character)value, dst);177if (wrap != null) return wrap;178return dst.cast(value);179}180181@SuppressWarnings("cast") // primitive cast to (long) is part of the pattern182static Object castToWrapperOrNull(long value, Class<?> dst) {183if (dst == int.class || dst == Integer.class)184return (int)(value);185if (dst == long.class || dst == Long.class)186return (long)(value);187if (dst == char.class || dst == Character.class)188return (char)(value);189if (dst == short.class || dst == Short.class)190return (short)(value);191if (dst == float.class || dst == Float.class)192return (float)(value);193if (dst == double.class || dst == Double.class)194return (double)(value);195if (dst == byte.class || dst == Byte.class)196return (byte)(value);197if (dst == boolean.class || dst == boolean.class)198return ((value % 29) & 1) == 0;199return null;200}201202static final int ONE_MILLION = (1000*1000), // first int value203TEN_BILLION = (10*1000*1000*1000), // scale factor to reach upper 32 bits204INITIAL_ARG_VAL = ONE_MILLION << 1; // <<1 makes space for sign bit;205static long nextArgVal;206static long nextArg(boolean moreBits) {207long val = nextArgVal++;208long sign = -(val & 1); // alternate signs209val >>= 1;210if (moreBits)211// Guarantee some bits in the high word.212// In any case keep the decimal representation simple-looking,213// with lots of zeroes, so as not to make the printed decimal214// strings unnecessarily noisy.215val += (val % ONE_MILLION) * TEN_BILLION;216return val ^ sign;217}218static int nextArg() {219// Produce a 32-bit result something like ONE_MILLION+(smallint).220// Example: 1_000_042.221return (int) nextArg(false);222}223static long nextArg(Class<?> kind) {224if (kind == long.class || kind == Long.class ||225kind == double.class || kind == Double.class)226// produce a 64-bit result something like227// ((TEN_BILLION+1) * (ONE_MILLION+(smallint)))228// Example: 10_000_420_001_000_042.229return nextArg(true);230return (long) nextArg();231}232233static Object randomArg(Class<?> param) {234Object wrap = castToWrapperOrNull(nextArg(param), param);235if (wrap != null) {236return wrap;237}238// import sun.invoke.util.Wrapper;239// Wrapper wrap = Wrapper.forBasicType(dst);240// if (wrap == Wrapper.OBJECT && Wrapper.isWrapperType(dst))241// wrap = Wrapper.forWrapperType(dst);242// if (wrap != Wrapper.OBJECT)243// return wrap.wrap(nextArg++);244if (param.isInterface()) {245for (Class<?> c : param.getClasses()) {246if (param.isAssignableFrom(c) && !c.isInterface())247{ param = c; break; }248}249}250if (param.isArray()) {251Class<?> ctype = param.getComponentType();252Object arg = Array.newInstance(ctype, 2);253Array.set(arg, 0, randomArg(ctype));254return arg;255}256if (param.isInterface() && param.isAssignableFrom(List.class))257return Arrays.asList("#"+nextArg());258if (param.isInterface() || param.isAssignableFrom(String.class))259return "#"+nextArg();260else261try {262return param.newInstance();263} catch (InstantiationException | IllegalAccessException ex) {264}265return null; // random class not Object, String, Integer, etc.266}267static Object[] randomArgs(Class<?>... params) {268Object[] args = new Object[params.length];269for (int i = 0; i < args.length; i++)270args[i] = randomArg(params[i]);271return args;272}273static Object[] randomArgs(int nargs, Class<?> param) {274Object[] args = new Object[nargs];275for (int i = 0; i < args.length; i++)276args[i] = randomArg(param);277return args;278}279static Object[] randomArgs(List<Class<?>> params) {280return randomArgs(params.toArray(new Class<?>[params.size()]));281}282283@SafeVarargs @SuppressWarnings("varargs")284static <T, E extends T> T[] array(Class<T[]> atype, E... a) {285return Arrays.copyOf(a, a.length, atype);286}287@SafeVarargs @SuppressWarnings("varargs")288static <T> T[] cat(T[] a, T... b) {289int alen = a.length, blen = b.length;290if (blen == 0) return a;291T[] c = Arrays.copyOf(a, alen + blen);292System.arraycopy(b, 0, c, alen, blen);293return c;294}295static Integer[] boxAll(int... vx) {296Integer[] res = new Integer[vx.length];297for (int i = 0; i < res.length; i++) {298res[i] = vx[i];299}300return res;301}302static Object getClasses(Object x) {303if (x == null) return x;304if (x instanceof String) return x; // keep the name305if (x instanceof List) {306// recursively report classes of the list elements307Object[] xa = ((List)x).toArray();308for (int i = 0; i < xa.length; i++)309xa[i] = getClasses(xa[i]);310return Arrays.asList(xa);311}312return x.getClass().getSimpleName();313}314315/** Return lambda(arg...[arity]) { new Object[]{ arg... } } */316static MethodHandle varargsList(int arity) {317return ValueConversions.varargsList(arity);318}319/** Return lambda(arg...[arity]) { Arrays.asList(arg...) } */320static MethodHandle varargsArray(int arity) {321return ValueConversions.varargsArray(arity);322}323static MethodHandle varargsArray(Class<?> arrayType, int arity) {324return ValueConversions.varargsArray(arrayType, arity);325}326/** Variation of varargsList, but with the given rtype. */327static MethodHandle varargsList(int arity, Class<?> rtype) {328MethodHandle list = varargsList(arity);329MethodType listType = list.type().changeReturnType(rtype);330if (List.class.isAssignableFrom(rtype) || rtype == void.class || rtype == Object.class) {331// OK332} else if (rtype.isAssignableFrom(String.class)) {333if (LIST_TO_STRING == null)334try {335LIST_TO_STRING = PRIVATE.findStatic(PRIVATE.lookupClass(), "listToString",336MethodType.methodType(String.class, List.class));337} catch (NoSuchMethodException | IllegalAccessException ex) { throw new RuntimeException(ex); }338list = MethodHandles.filterReturnValue(list, LIST_TO_STRING);339} else if (rtype.isPrimitive()) {340if (LIST_TO_INT == null)341try {342LIST_TO_INT = PRIVATE.findStatic(PRIVATE.lookupClass(), "listToInt",343MethodType.methodType(int.class, List.class));344} catch (NoSuchMethodException | IllegalAccessException ex) { throw new RuntimeException(ex); }345list = MethodHandles.filterReturnValue(list, LIST_TO_INT);346list = MethodHandles.explicitCastArguments(list, listType);347} else {348throw new RuntimeException("varargsList: "+rtype);349}350return list.asType(listType);351}352/** Variation of varargsList, but with the given ptypes and rtype. */353static MethodHandle varargsList(List<Class<?>> ptypes, Class<?> rtype) {354MethodHandle list = varargsList(ptypes.size(), rtype);355return list.asType(MethodType.methodType(rtype, ptypes));356}357private static MethodHandle LIST_TO_STRING, LIST_TO_INT;358private static String listToString(List<?> x) { return x.toString(); }359private static int listToInt(List<?> x) { return x.toString().hashCode(); }360361static MethodHandle changeArgTypes(MethodHandle target, Class<?> argType) {362return changeArgTypes(target, 0, 999, argType);363}364static MethodHandle changeArgTypes(MethodHandle target,365int beg, int end, Class<?> argType) {366MethodType targetType = target.type();367end = Math.min(end, targetType.parameterCount());368ArrayList<Class<?>> argTypes = new ArrayList<>(targetType.parameterList());369Collections.fill(argTypes.subList(beg, end), argType);370MethodType ttype2 = MethodType.methodType(targetType.returnType(), argTypes);371return target.asType(ttype2);372}373static MethodHandle addTrailingArgs(MethodHandle target, int nargs, Class<?> argClass) {374int targetLen = target.type().parameterCount();375int extra = (nargs - targetLen);376if (extra <= 0) return target;377List<Class<?>> fakeArgs = Collections.<Class<?>>nCopies(extra, argClass);378return MethodHandles.dropArguments(target, targetLen, fakeArgs);379}380381// This lookup is good for all members in and under MethodHandlesTest.382static final Lookup PRIVATE = MethodHandles.lookup();383// This lookup is good for package-private members but not private ones.384static final Lookup PACKAGE = PackageSibling.lookup();385// This lookup is good for public members and protected members of PubExample386static final Lookup SUBCLASS = RemoteExample.lookup();387// This lookup is good only for public members.388static final Lookup PUBLIC = MethodHandles.publicLookup();389390// Subject methods...391static class Example implements IntExample {392final String name;393public Example() { name = "Example#"+nextArg(); }394protected Example(String name) { this.name = name; }395@SuppressWarnings("LeakingThisInConstructor")396protected Example(int x) { this(); called("protected <init>", this, x); }397//Example(Void x) { does not exist; lookup elicts NoSuchMethodException }398@Override public String toString() { return name; }399400public void v0() { called("v0", this); }401protected void pro_v0() { called("pro_v0", this); }402void pkg_v0() { called("pkg_v0", this); }403private void pri_v0() { called("pri_v0", this); }404public static void s0() { called("s0"); }405protected static void pro_s0() { called("pro_s0"); }406static void pkg_s0() { called("pkg_s0"); }407private static void pri_s0() { called("pri_s0"); }408409public Object v1(Object x) { return called("v1", this, x); }410public Object v2(Object x, Object y) { return called("v2", this, x, y); }411public Object v2(Object x, int y) { return called("v2", this, x, y); }412public Object v2(int x, Object y) { return called("v2", this, x, y); }413public Object v2(int x, int y) { return called("v2", this, x, y); }414public static Object s1(Object x) { return called("s1", x); }415public static Object s2(int x) { return called("s2", x); }416public static Object s3(long x) { return called("s3", x); }417public static Object s4(int x, int y) { return called("s4", x, y); }418public static Object s5(long x, int y) { return called("s5", x, y); }419public static Object s6(int x, long y) { return called("s6", x, y); }420public static Object s7(float x, double y) { return called("s7", x, y); }421422// for testing findConstructor:423public Example(String x, int y) { this.name = x+y; called("Example.<init>", x, y); }424public Example(int x, String y) { this.name = x+y; called("Example.<init>", x, y); }425public Example(int x, int y) { this.name = x+""+y; called("Example.<init>", x, y); }426public Example(int x, long y) { this.name = x+""+y; called("Example.<init>", x, y); }427public Example(int x, float y) { this.name = x+""+y; called("Example.<init>", x, y); }428public Example(int x, double y) { this.name = x+""+y; called("Example.<init>", x, y); }429public Example(int x, int y, int z) { this.name = x+""+y+""+z; called("Example.<init>", x, y, z); }430public Example(int x, int y, int z, int a) { this.name = x+""+y+""+z+""+a; called("Example.<init>", x, y, z, a); }431432static final Lookup EXAMPLE = MethodHandles.lookup(); // for testing findSpecial433}434static final Lookup EXAMPLE = Example.EXAMPLE;435public static class PubExample extends Example {436public PubExample() { this("PubExample"); }437protected PubExample(String prefix) { super(prefix+"#"+nextArg()); }438protected void pro_v0() { called("Pub/pro_v0", this); }439protected static void pro_s0() { called("Pub/pro_s0"); }440}441static class SubExample extends Example {442@Override public void v0() { called("Sub/v0", this); }443@Override void pkg_v0() { called("Sub/pkg_v0", this); }444@SuppressWarnings("LeakingThisInConstructor")445private SubExample(int x) { called("<init>", this, x); }446public SubExample() { super("SubExample#"+nextArg()); }447}448public static interface IntExample {449public void v0();450public static class Impl implements IntExample {451public void v0() { called("Int/v0", this); }452final String name;453public Impl() { name = "Impl#"+nextArg(); }454@Override public String toString() { return name; }455}456}457static interface SubIntExample extends IntExample { }458459static final Object[][][] ACCESS_CASES = {460{ { false, PUBLIC }, { false, SUBCLASS }, { false, PACKAGE }, { false, PRIVATE }, { false, EXAMPLE } }, //[0]: all false461{ { false, PUBLIC }, { false, SUBCLASS }, { false, PACKAGE }, { true, PRIVATE }, { true, EXAMPLE } }, //[1]: only PRIVATE462{ { false, PUBLIC }, { false, SUBCLASS }, { true, PACKAGE }, { true, PRIVATE }, { true, EXAMPLE } }, //[2]: PUBLIC false463{ { false, PUBLIC }, { true, SUBCLASS }, { true, PACKAGE }, { true, PRIVATE }, { true, EXAMPLE } }, //[3]: subclass OK464{ { true, PUBLIC }, { true, SUBCLASS }, { true, PACKAGE }, { true, PRIVATE }, { true, EXAMPLE } }, //[4]: all true465};466467static Object[][] accessCases(Class<?> defc, String name, boolean isSpecial) {468Object[][] cases;469if (name.contains("pri_") || isSpecial) {470cases = ACCESS_CASES[1]; // PRIVATE only471} else if (name.contains("pkg_") || !Modifier.isPublic(defc.getModifiers())) {472cases = ACCESS_CASES[2]; // not PUBLIC473} else if (name.contains("pro_")) {474cases = ACCESS_CASES[3]; // PUBLIC class, protected member475} else {476assertTrue(name.indexOf('_') < 0 || name.contains("fin_"));477boolean pubc = Modifier.isPublic(defc.getModifiers());478if (pubc)479cases = ACCESS_CASES[4]; // all access levels480else481cases = ACCESS_CASES[2]; // PACKAGE but not PUBLIC482}483if (defc != Example.class && cases[cases.length-1][1] == EXAMPLE)484cases = Arrays.copyOfRange(cases, 0, cases.length-1);485return cases;486}487static Object[][] accessCases(Class<?> defc, String name) {488return accessCases(defc, name, false);489}490491static Lookup maybeMoveIn(Lookup lookup, Class<?> defc) {492if (lookup == PUBLIC || lookup == SUBCLASS || lookup == PACKAGE)493// external views stay external494return lookup;495return lookup.in(defc);496}497498/** Is findVirtual (etc.) of "<init<" supposed to elicit a NoSuchMethodException? */499final static boolean INIT_REF_CAUSES_NSME = true;500501@Test502public void testFindStatic() throws Throwable {503CodeCacheOverflowProcessor.runMHTest(this::testFindStatic0);504}505506public void testFindStatic0() throws Throwable {507if (CAN_SKIP_WORKING) return;508startTest("findStatic");509testFindStatic(PubExample.class, void.class, "s0");510testFindStatic(Example.class, void.class, "s0");511testFindStatic(Example.class, void.class, "pkg_s0");512testFindStatic(Example.class, void.class, "pri_s0");513testFindStatic(Example.class, void.class, "pro_s0");514testFindStatic(PubExample.class, void.class, "Pub/pro_s0");515516testFindStatic(Example.class, Object.class, "s1", Object.class);517testFindStatic(Example.class, Object.class, "s2", int.class);518testFindStatic(Example.class, Object.class, "s3", long.class);519testFindStatic(Example.class, Object.class, "s4", int.class, int.class);520testFindStatic(Example.class, Object.class, "s5", long.class, int.class);521testFindStatic(Example.class, Object.class, "s6", int.class, long.class);522testFindStatic(Example.class, Object.class, "s7", float.class, double.class);523524testFindStatic(false, PRIVATE, Example.class, void.class, "bogus");525testFindStatic(false, PRIVATE, Example.class, void.class, "<init>", int.class);526testFindStatic(false, PRIVATE, Example.class, void.class, "<init>", Void.class);527testFindStatic(false, PRIVATE, Example.class, void.class, "v0");528}529530void testFindStatic(Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {531for (Object[] ac : accessCases(defc, name)) {532testFindStatic((Boolean)ac[0], (Lookup)ac[1], defc, ret, name, params);533}534}535void testFindStatic(Lookup lookup, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {536testFindStatic(true, lookup, defc, ret, name, params);537}538void testFindStatic(boolean positive, Lookup lookup, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {539countTest(positive);540String methodName = name.substring(1 + name.indexOf('/')); // foo/bar => foo541MethodType type = MethodType.methodType(ret, params);542MethodHandle target = null;543Exception noAccess = null;544try {545if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type);546target = maybeMoveIn(lookup, defc).findStatic(defc, methodName, type);547} catch (ReflectiveOperationException ex) {548noAccess = ex;549assertExceptionClass(550(name.contains("bogus") || INIT_REF_CAUSES_NSME && name.contains("<init>"))551? NoSuchMethodException.class552: IllegalAccessException.class,553noAccess);554if (verbosity >= 5) ex.printStackTrace(System.out);555}556if (verbosity >= 3)557System.out.println("findStatic "+lookup+": "+defc.getName()+"."+name+"/"+type+" => "+target558+(noAccess == null ? "" : " !! "+noAccess));559if (positive && noAccess != null) throw noAccess;560assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null);561if (!positive) return; // negative test failed as expected562assertEquals(type, target.type());563assertNameStringContains(target, methodName);564Object[] args = randomArgs(params);565printCalled(target, name, args);566target.invokeWithArguments(args);567assertCalled(name, args);568if (verbosity >= 1)569System.out.print(':');570}571572static void assertExceptionClass(Class<? extends Throwable> expected,573Throwable actual) {574if (expected.isInstance(actual)) return;575actual.printStackTrace();576assertEquals(expected, actual.getClass());577}578579static final boolean DEBUG_METHOD_HANDLE_NAMES = Boolean.getBoolean("java.lang.invoke.MethodHandle.DEBUG_NAMES");580581// rough check of name string582static void assertNameStringContains(MethodHandle x, String s) {583if (!DEBUG_METHOD_HANDLE_NAMES) {584// ignore s585assertEquals("MethodHandle"+x.type(), x.toString());586return;587}588if (x.toString().contains(s)) return;589assertEquals(s, x);590}591592@Test593public void testFindVirtual() throws Throwable {594CodeCacheOverflowProcessor.runMHTest(this::testFindVirtual0);595}596597public void testFindVirtual0() throws Throwable {598if (CAN_SKIP_WORKING) return;599startTest("findVirtual");600testFindVirtual(Example.class, void.class, "v0");601testFindVirtual(Example.class, void.class, "pkg_v0");602testFindVirtual(Example.class, void.class, "pri_v0");603testFindVirtual(Example.class, Object.class, "v1", Object.class);604testFindVirtual(Example.class, Object.class, "v2", Object.class, Object.class);605testFindVirtual(Example.class, Object.class, "v2", Object.class, int.class);606testFindVirtual(Example.class, Object.class, "v2", int.class, Object.class);607testFindVirtual(Example.class, Object.class, "v2", int.class, int.class);608testFindVirtual(Example.class, void.class, "pro_v0");609testFindVirtual(PubExample.class, void.class, "Pub/pro_v0");610611testFindVirtual(false, PRIVATE, Example.class, Example.class, void.class, "bogus");612testFindVirtual(false, PRIVATE, Example.class, Example.class, void.class, "<init>", int.class);613testFindVirtual(false, PRIVATE, Example.class, Example.class, void.class, "<init>", Void.class);614testFindVirtual(false, PRIVATE, Example.class, Example.class, void.class, "s0");615616// test dispatch617testFindVirtual(SubExample.class, SubExample.class, void.class, "Sub/v0");618testFindVirtual(SubExample.class, Example.class, void.class, "Sub/v0");619testFindVirtual(SubExample.class, IntExample.class, void.class, "Sub/v0");620testFindVirtual(SubExample.class, SubExample.class, void.class, "Sub/pkg_v0");621testFindVirtual(SubExample.class, Example.class, void.class, "Sub/pkg_v0");622testFindVirtual(Example.class, IntExample.class, void.class, "v0");623testFindVirtual(IntExample.Impl.class, IntExample.class, void.class, "Int/v0");624}625626@Test627public void testFindVirtualClone() throws Throwable {628CodeCacheOverflowProcessor.runMHTest(this::testFindVirtualClone0);629}630631public void testFindVirtualClone0() throws Throwable {632// test some ad hoc system methods633testFindVirtual(false, PUBLIC, Object.class, Object.class, "clone");634testFindVirtual(true, PUBLIC, Object[].class, Object.class, "clone");635testFindVirtual(true, PUBLIC, int[].class, Object.class, "clone");636for (Class<?> cls : new Class<?>[]{ boolean[].class, long[].class, float[].class, char[].class })637testFindVirtual(true, PUBLIC, cls, Object.class, "clone");638}639640void testFindVirtual(Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {641Class<?> rcvc = defc;642testFindVirtual(rcvc, defc, ret, name, params);643}644void testFindVirtual(Class<?> rcvc, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {645for (Object[] ac : accessCases(defc, name)) {646testFindVirtual((Boolean)ac[0], (Lookup)ac[1], rcvc, defc, ret, name, params);647}648}649void testFindVirtual(Lookup lookup, Class<?> rcvc, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {650testFindVirtual(true, lookup, rcvc, defc, ret, name, params);651}652void testFindVirtual(boolean positive, Lookup lookup, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {653testFindVirtual(positive, lookup, defc, defc, ret, name, params);654}655void testFindVirtual(boolean positive, Lookup lookup, Class<?> rcvc, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {656countTest(positive);657String methodName = name.substring(1 + name.indexOf('/')); // foo/bar => foo658MethodType type = MethodType.methodType(ret, params);659MethodHandle target = null;660Exception noAccess = null;661try {662if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type);663target = maybeMoveIn(lookup, defc).findVirtual(defc, methodName, type);664} catch (ReflectiveOperationException ex) {665noAccess = ex;666assertExceptionClass(667(name.contains("bogus") || INIT_REF_CAUSES_NSME && name.contains("<init>"))668? NoSuchMethodException.class669: IllegalAccessException.class,670noAccess);671if (verbosity >= 5) ex.printStackTrace(System.out);672}673if (verbosity >= 3)674System.out.println("findVirtual "+lookup+": "+defc.getName()+"."+name+"/"+type+" => "+target675+(noAccess == null ? "" : " !! "+noAccess));676if (positive && noAccess != null) throw noAccess;677assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null);678if (!positive) return; // negative test failed as expected679Class<?> selfc = defc;680// predict receiver type narrowing:681if (lookup == SUBCLASS &&682name.contains("pro_") &&683selfc.isAssignableFrom(lookup.lookupClass())) {684selfc = lookup.lookupClass();685if (name.startsWith("Pub/")) name = "Rem/"+name.substring(4);686}687Class<?>[] paramsWithSelf = cat(array(Class[].class, (Class)selfc), params);688MethodType typeWithSelf = MethodType.methodType(ret, paramsWithSelf);689assertEquals(typeWithSelf, target.type());690assertNameStringContains(target, methodName);691Object[] argsWithSelf = randomArgs(paramsWithSelf);692if (selfc.isAssignableFrom(rcvc) && rcvc != selfc) argsWithSelf[0] = randomArg(rcvc);693printCalled(target, name, argsWithSelf);694Object res = target.invokeWithArguments(argsWithSelf);695if (Example.class.isAssignableFrom(defc) || IntExample.class.isAssignableFrom(defc)) {696assertCalled(name, argsWithSelf);697} else if (name.equals("clone")) {698// Ad hoc method call outside Example. For Object[].clone.699printCalled(target, name, argsWithSelf);700assertEquals(MethodType.methodType(Object.class, rcvc), target.type());701Object orig = argsWithSelf[0];702assertEquals(orig.getClass(), res.getClass());703if (res instanceof Object[])704assertArrayEquals((Object[])res, (Object[])argsWithSelf[0]);705assert(Arrays.deepEquals(new Object[]{res}, new Object[]{argsWithSelf[0]}));706} else {707assert(false) : Arrays.asList(positive, lookup, rcvc, defc, ret, name, deepToString(params));708}709if (verbosity >= 1)710System.out.print(':');711}712713@Test714public void testFindSpecial() throws Throwable {715CodeCacheOverflowProcessor.runMHTest(this::testFindSpecial0);716}717718public void testFindSpecial0() throws Throwable {719if (CAN_SKIP_WORKING) return;720startTest("findSpecial");721testFindSpecial(SubExample.class, Example.class, void.class, "v0");722testFindSpecial(SubExample.class, Example.class, void.class, "pkg_v0");723testFindSpecial(RemoteExample.class, PubExample.class, void.class, "Pub/pro_v0");724// Do some negative testing:725for (Lookup lookup : new Lookup[]{ PRIVATE, EXAMPLE, PACKAGE, PUBLIC }) {726testFindSpecial(false, lookup, Object.class, Example.class, void.class, "v0");727testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "bogus");728testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "<init>", int.class);729testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "<init>", Void.class);730testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "s0");731}732}733734void testFindSpecial(Class<?> specialCaller,735Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {736if (specialCaller == RemoteExample.class) {737testFindSpecial(false, EXAMPLE, specialCaller, defc, ret, name, params);738testFindSpecial(false, PRIVATE, specialCaller, defc, ret, name, params);739testFindSpecial(false, PACKAGE, specialCaller, defc, ret, name, params);740testFindSpecial(true, SUBCLASS, specialCaller, defc, ret, name, params);741testFindSpecial(false, PUBLIC, specialCaller, defc, ret, name, params);742return;743}744testFindSpecial(true, EXAMPLE, specialCaller, defc, ret, name, params);745testFindSpecial(true, PRIVATE, specialCaller, defc, ret, name, params);746testFindSpecial(false, PACKAGE, specialCaller, defc, ret, name, params);747testFindSpecial(false, SUBCLASS, specialCaller, defc, ret, name, params);748testFindSpecial(false, PUBLIC, specialCaller, defc, ret, name, params);749}750void testFindSpecial(boolean positive, Lookup lookup, Class<?> specialCaller,751Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {752countTest(positive);753String methodName = name.substring(1 + name.indexOf('/')); // foo/bar => foo754MethodType type = MethodType.methodType(ret, params);755Lookup specialLookup = maybeMoveIn(lookup, specialCaller);756boolean specialAccessOK = (specialLookup.lookupClass() == specialCaller &&757(specialLookup.lookupModes() & Lookup.PRIVATE) != 0);758MethodHandle target = null;759Exception noAccess = null;760try {761if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type);762if (verbosity >= 5) System.out.println(" lookup => "+specialLookup);763target = specialLookup.findSpecial(defc, methodName, type, specialCaller);764} catch (ReflectiveOperationException ex) {765noAccess = ex;766assertExceptionClass(767(!specialAccessOK) // this check should happen first768? IllegalAccessException.class769: (name.contains("bogus") || INIT_REF_CAUSES_NSME && name.contains("<init>"))770? NoSuchMethodException.class771: IllegalAccessException.class,772noAccess);773if (verbosity >= 5) ex.printStackTrace(System.out);774}775if (verbosity >= 3)776System.out.println("findSpecial from "+specialCaller.getName()+" to "+defc.getName()+"."+name+"/"+type+" => "+target777+(target == null ? "" : target.type())778+(noAccess == null ? "" : " !! "+noAccess));779if (positive && noAccess != null) throw noAccess;780assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null);781if (!positive) return; // negative test failed as expected782assertEquals(specialCaller, target.type().parameterType(0));783assertEquals(type, target.type().dropParameterTypes(0,1));784Class<?>[] paramsWithSelf = cat(array(Class[].class, (Class)specialCaller), params);785MethodType typeWithSelf = MethodType.methodType(ret, paramsWithSelf);786assertNameStringContains(target, methodName);787Object[] args = randomArgs(paramsWithSelf);788printCalled(target, name, args);789target.invokeWithArguments(args);790assertCalled(name, args);791}792793@Test794public void testFindConstructor() throws Throwable {795CodeCacheOverflowProcessor.runMHTest(this::testFindConstructor0);796}797798public void testFindConstructor0() throws Throwable {799if (CAN_SKIP_WORKING) return;800startTest("findConstructor");801testFindConstructor(true, EXAMPLE, Example.class);802testFindConstructor(true, EXAMPLE, Example.class, int.class);803testFindConstructor(true, EXAMPLE, Example.class, int.class, int.class);804testFindConstructor(true, EXAMPLE, Example.class, int.class, long.class);805testFindConstructor(true, EXAMPLE, Example.class, int.class, float.class);806testFindConstructor(true, EXAMPLE, Example.class, int.class, double.class);807testFindConstructor(true, EXAMPLE, Example.class, String.class);808testFindConstructor(true, EXAMPLE, Example.class, int.class, int.class, int.class);809testFindConstructor(true, EXAMPLE, Example.class, int.class, int.class, int.class, int.class);810}811void testFindConstructor(boolean positive, Lookup lookup,812Class<?> defc, Class<?>... params) throws Throwable {813countTest(positive);814MethodType type = MethodType.methodType(void.class, params);815MethodHandle target = null;816Exception noAccess = null;817try {818if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" <init>"+type);819target = lookup.findConstructor(defc, type);820} catch (ReflectiveOperationException ex) {821noAccess = ex;822assertTrue(noAccess.getClass().getName(), noAccess instanceof IllegalAccessException);823}824if (verbosity >= 3)825System.out.println("findConstructor "+defc.getName()+".<init>/"+type+" => "+target826+(target == null ? "" : target.type())827+(noAccess == null ? "" : " !! "+noAccess));828if (positive && noAccess != null) throw noAccess;829assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null);830if (!positive) return; // negative test failed as expected831assertEquals(type.changeReturnType(defc), target.type());832Object[] args = randomArgs(params);833printCalled(target, defc.getSimpleName(), args);834Object obj = target.invokeWithArguments(args);835if (!(defc == Example.class && params.length < 2))836assertCalled(defc.getSimpleName()+".<init>", args);837assertTrue("instance of "+defc.getName(), defc.isInstance(obj));838}839840@Test841public void testBind() throws Throwable {842CodeCacheOverflowProcessor.runMHTest(this::testBind0);843}844845public void testBind0() throws Throwable {846if (CAN_SKIP_WORKING) return;847startTest("bind");848testBind(Example.class, void.class, "v0");849testBind(Example.class, void.class, "pkg_v0");850testBind(Example.class, void.class, "pri_v0");851testBind(Example.class, Object.class, "v1", Object.class);852testBind(Example.class, Object.class, "v2", Object.class, Object.class);853testBind(Example.class, Object.class, "v2", Object.class, int.class);854testBind(Example.class, Object.class, "v2", int.class, Object.class);855testBind(Example.class, Object.class, "v2", int.class, int.class);856testBind(false, PRIVATE, Example.class, void.class, "bogus");857testBind(false, PRIVATE, Example.class, void.class, "<init>", int.class);858testBind(false, PRIVATE, Example.class, void.class, "<init>", Void.class);859testBind(SubExample.class, void.class, "Sub/v0");860testBind(SubExample.class, void.class, "Sub/pkg_v0");861testBind(IntExample.Impl.class, void.class, "Int/v0");862}863864void testBind(Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {865for (Object[] ac : accessCases(defc, name)) {866testBind((Boolean)ac[0], (Lookup)ac[1], defc, ret, name, params);867}868}869870void testBind(boolean positive, Lookup lookup, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {871countTest(positive);872String methodName = name.substring(1 + name.indexOf('/')); // foo/bar => foo873MethodType type = MethodType.methodType(ret, params);874Object receiver = randomArg(defc);875MethodHandle target = null;876Exception noAccess = null;877try {878if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type);879target = maybeMoveIn(lookup, defc).bind(receiver, methodName, type);880} catch (ReflectiveOperationException ex) {881noAccess = ex;882assertExceptionClass(883(name.contains("bogus") || INIT_REF_CAUSES_NSME && name.contains("<init>"))884? NoSuchMethodException.class885: IllegalAccessException.class,886noAccess);887if (verbosity >= 5) ex.printStackTrace(System.out);888}889if (verbosity >= 3)890System.out.println("bind "+receiver+"."+name+"/"+type+" => "+target891+(noAccess == null ? "" : " !! "+noAccess));892if (positive && noAccess != null) throw noAccess;893assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null);894if (!positive) return; // negative test failed as expected895assertEquals(type, target.type());896Object[] args = randomArgs(params);897printCalled(target, name, args);898target.invokeWithArguments(args);899Object[] argsWithReceiver = cat(array(Object[].class, receiver), args);900assertCalled(name, argsWithReceiver);901if (verbosity >= 1)902System.out.print(':');903}904905@Test906public void testUnreflect() throws Throwable {907CodeCacheOverflowProcessor.runMHTest(this::testUnreflect0);908}909910public void testUnreflect0() throws Throwable {911if (CAN_SKIP_WORKING) return;912startTest("unreflect");913testUnreflect(Example.class, true, void.class, "s0");914testUnreflect(Example.class, true, void.class, "pro_s0");915testUnreflect(Example.class, true, void.class, "pkg_s0");916testUnreflect(Example.class, true, void.class, "pri_s0");917918testUnreflect(Example.class, true, Object.class, "s1", Object.class);919testUnreflect(Example.class, true, Object.class, "s2", int.class);920testUnreflect(Example.class, true, Object.class, "s3", long.class);921testUnreflect(Example.class, true, Object.class, "s4", int.class, int.class);922testUnreflect(Example.class, true, Object.class, "s5", long.class, int.class);923testUnreflect(Example.class, true, Object.class, "s6", int.class, long.class);924925testUnreflect(Example.class, false, void.class, "v0");926testUnreflect(Example.class, false, void.class, "pkg_v0");927testUnreflect(Example.class, false, void.class, "pri_v0");928testUnreflect(Example.class, false, Object.class, "v1", Object.class);929testUnreflect(Example.class, false, Object.class, "v2", Object.class, Object.class);930testUnreflect(Example.class, false, Object.class, "v2", Object.class, int.class);931testUnreflect(Example.class, false, Object.class, "v2", int.class, Object.class);932testUnreflect(Example.class, false, Object.class, "v2", int.class, int.class);933934// Test a public final member in another package:935testUnreflect(RemoteExample.class, false, void.class, "Rem/fin_v0");936}937938void testUnreflect(Class<?> defc, boolean isStatic, Class<?> ret, String name, Class<?>... params) throws Throwable {939for (Object[] ac : accessCases(defc, name)) {940testUnreflectMaybeSpecial(null, (Boolean)ac[0], (Lookup)ac[1], defc, (isStatic ? null : defc), ret, name, params);941}942}943void testUnreflect(Class<?> defc, Class<?> rcvc, Class<?> ret, String name, Class<?>... params) throws Throwable {944for (Object[] ac : accessCases(defc, name)) {945testUnreflectMaybeSpecial(null, (Boolean)ac[0], (Lookup)ac[1], defc, rcvc, ret, name, params);946}947}948void testUnreflectMaybeSpecial(Class<?> specialCaller,949boolean positive, Lookup lookup,950Class<?> defc, Class<?> rcvc, Class<?> ret, String name, Class<?>... params) throws Throwable {951countTest(positive);952String methodName = name.substring(1 + name.indexOf('/')); // foo/bar => foo953MethodType type = MethodType.methodType(ret, params);954Lookup specialLookup = (specialCaller != null ? maybeMoveIn(lookup, specialCaller) : null);955boolean specialAccessOK = (specialCaller != null &&956specialLookup.lookupClass() == specialCaller &&957(specialLookup.lookupModes() & Lookup.PRIVATE) != 0);958Method rmethod = defc.getDeclaredMethod(methodName, params);959MethodHandle target = null;960Exception noAccess = null;961boolean isStatic = (rcvc == null);962boolean isSpecial = (specialCaller != null);963try {964if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type);965if (isSpecial)966target = specialLookup.unreflectSpecial(rmethod, specialCaller);967else968target = maybeMoveIn(lookup, defc).unreflect(rmethod);969} catch (ReflectiveOperationException ex) {970noAccess = ex;971assertExceptionClass(972IllegalAccessException.class, // NSME is impossible, since it was already reflected973noAccess);974if (verbosity >= 5) ex.printStackTrace(System.out);975}976if (verbosity >= 3)977System.out.println("unreflect"+(isSpecial?"Special":"")+" "+defc.getName()+"."+name+"/"+type978+(!isSpecial ? "" : " specialCaller="+specialCaller)979+( isStatic ? "" : " receiver="+rcvc)980+" => "+target981+(noAccess == null ? "" : " !! "+noAccess));982if (positive && noAccess != null) throw noAccess;983assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null);984if (!positive) return; // negative test failed as expected985assertEquals(isStatic, Modifier.isStatic(rmethod.getModifiers()));986Class<?>[] paramsMaybeWithSelf = params;987if (!isStatic) {988paramsMaybeWithSelf = cat(array(Class[].class, (Class)rcvc), params);989}990MethodType typeMaybeWithSelf = MethodType.methodType(ret, paramsMaybeWithSelf);991if (isStatic) {992assertEquals(typeMaybeWithSelf, target.type());993} else {994if (isSpecial)995assertEquals(specialCaller, target.type().parameterType(0));996else997assertEquals(defc, target.type().parameterType(0));998assertEquals(typeMaybeWithSelf, target.type().changeParameterType(0, rcvc));999}1000Object[] argsMaybeWithSelf = randomArgs(paramsMaybeWithSelf);1001printCalled(target, name, argsMaybeWithSelf);1002target.invokeWithArguments(argsMaybeWithSelf);1003assertCalled(name, argsMaybeWithSelf);1004if (verbosity >= 1)1005System.out.print(':');1006}10071008void testUnreflectSpecial(Class<?> defc, Class<?> rcvc, Class<?> ret, String name, Class<?>... params) throws Throwable {1009for (Object[] ac : accessCases(defc, name, true)) {1010Class<?> specialCaller = rcvc;1011testUnreflectMaybeSpecial(specialCaller, (Boolean)ac[0], (Lookup)ac[1], defc, rcvc, ret, name, params);1012}1013}10141015@Test1016public void testUnreflectSpecial() throws Throwable {1017CodeCacheOverflowProcessor.runMHTest(this::testUnreflectSpecial0);1018}10191020public void testUnreflectSpecial0() throws Throwable {1021if (CAN_SKIP_WORKING) return;1022startTest("unreflectSpecial");1023testUnreflectSpecial(Example.class, Example.class, void.class, "v0");1024testUnreflectSpecial(Example.class, SubExample.class, void.class, "v0");1025testUnreflectSpecial(Example.class, Example.class, void.class, "pkg_v0");1026testUnreflectSpecial(Example.class, SubExample.class, void.class, "pkg_v0");1027testUnreflectSpecial(Example.class, Example.class, Object.class, "v2", int.class, int.class);1028testUnreflectSpecial(Example.class, SubExample.class, Object.class, "v2", int.class, int.class);1029testUnreflectMaybeSpecial(Example.class, false, PRIVATE, Example.class, Example.class, void.class, "s0");1030}10311032public static class HasFields {1033boolean fZ = false;1034byte fB = (byte)'B';1035short fS = (short)'S';1036char fC = 'C';1037int fI = 'I';1038long fJ = 'J';1039float fF = 'F';1040double fD = 'D';1041static boolean sZ = true;1042static byte sB = 1+(byte)'B';1043static short sS = 1+(short)'S';1044static char sC = 1+'C';1045static int sI = 1+'I';1046static long sJ = 1+'J';1047static float sF = 1+'F';1048static double sD = 1+'D';10491050Object fL = 'L';1051String fR = "R";1052static Object sL = 'M';1053static String sR = "S";10541055static final Object[][] CASES;1056static {1057ArrayList<Object[]> cases = new ArrayList<>();1058Object types[][] = {1059{'L',Object.class}, {'R',String.class},1060{'I',int.class}, {'J',long.class},1061{'F',float.class}, {'D',double.class},1062{'Z',boolean.class}, {'B',byte.class},1063{'S',short.class}, {'C',char.class},1064};1065HasFields fields = new HasFields();1066for (Object[] t : types) {1067for (int kind = 0; kind <= 1; kind++) {1068boolean isStatic = (kind != 0);1069char btc = (Character)t[0];1070String name = (isStatic ? "s" : "f") + btc;1071Class<?> type = (Class<?>) t[1];1072Object value;1073Field field;1074try {1075field = HasFields.class.getDeclaredField(name);1076} catch (NoSuchFieldException | SecurityException ex) {1077throw new InternalError("no field HasFields."+name);1078}1079try {1080value = field.get(fields);1081} catch (IllegalArgumentException | IllegalAccessException ex) {1082throw new InternalError("cannot fetch field HasFields."+name);1083}1084if (type == float.class) {1085float v = 'F';1086if (isStatic) v++;1087assertTrue(value.equals(v));1088}1089assertTrue(name.equals(field.getName()));1090assertTrue(type.equals(field.getType()));1091assertTrue(isStatic == (Modifier.isStatic(field.getModifiers())));1092cases.add(new Object[]{ field, value });1093}1094}1095cases.add(new Object[]{ new Object[]{ false, HasFields.class, "bogus_fD", double.class }, Error.class });1096cases.add(new Object[]{ new Object[]{ true, HasFields.class, "bogus_sL", Object.class }, Error.class });1097CASES = cases.toArray(new Object[0][]);1098}1099}11001101static final int TEST_UNREFLECT = 1, TEST_FIND_FIELD = 2, TEST_FIND_STATIC = 3, TEST_SETTER = 0x10, TEST_BOUND = 0x20, TEST_NPE = 0x40;1102static boolean testModeMatches(int testMode, boolean isStatic) {1103switch (testMode) {1104case TEST_FIND_STATIC: return isStatic;1105case TEST_FIND_FIELD: return !isStatic;1106case TEST_UNREFLECT: return true; // unreflect matches both1107}1108throw new InternalError("testMode="+testMode);1109}11101111@Test1112public void testUnreflectGetter() throws Throwable {1113CodeCacheOverflowProcessor.runMHTest(this::testUnreflectGetter0);1114}11151116public void testUnreflectGetter0() throws Throwable {1117if (CAN_SKIP_WORKING) return;1118startTest("unreflectGetter");1119testGetter(TEST_UNREFLECT);1120}11211122@Test1123public void testFindGetter() throws Throwable {1124CodeCacheOverflowProcessor.runMHTest(this::testFindGetter0);1125}11261127public void testFindGetter0() throws Throwable {1128if (CAN_SKIP_WORKING) return;1129startTest("findGetter");1130testGetter(TEST_FIND_FIELD);1131testGetter(TEST_FIND_FIELD | TEST_BOUND);1132}11331134@Test1135public void testFindStaticGetter() throws Throwable {1136CodeCacheOverflowProcessor.runMHTest(this::testFindStaticGetter0);1137}11381139public void testFindStaticGetter0() throws Throwable {1140if (CAN_SKIP_WORKING) return;1141startTest("findStaticGetter");1142testGetter(TEST_FIND_STATIC);1143}11441145public void testGetter(int testMode) throws Throwable {1146Lookup lookup = PRIVATE; // FIXME: test more lookups than this one1147for (Object[] c : HasFields.CASES) {1148boolean positive = (c[1] != Error.class);1149testGetter(positive, lookup, c[0], c[1], testMode);1150if (positive)1151testGetter(positive, lookup, c[0], c[1], testMode | TEST_NPE);1152}1153testGetter(true, lookup,1154new Object[]{ true, System.class, "out", java.io.PrintStream.class },1155System.out, testMode);1156for (int isStaticN = 0; isStaticN <= 1; isStaticN++) {1157testGetter(false, lookup,1158new Object[]{ (isStaticN != 0), System.class, "bogus", char.class },1159null, testMode);1160}1161}1162public void testGetter(boolean positive, MethodHandles.Lookup lookup,1163Object fieldRef, Object value, int testMode) throws Throwable {1164testAccessor(positive, lookup, fieldRef, value, testMode);1165}11661167public void testAccessor(boolean positive0, MethodHandles.Lookup lookup,1168Object fieldRef, Object value, int testMode0) throws Throwable {1169if (verbosity >= 4)1170System.out.println("testAccessor"+Arrays.deepToString(new Object[]{positive0, lookup, fieldRef, value, testMode0}));1171boolean isGetter = ((testMode0 & TEST_SETTER) == 0);1172boolean doBound = ((testMode0 & TEST_BOUND) != 0);1173boolean testNPE = ((testMode0 & TEST_NPE) != 0);1174int testMode = testMode0 & ~(TEST_SETTER | TEST_BOUND | TEST_NPE);1175boolean positive = positive0 && !testNPE;1176boolean isStatic;1177Class<?> fclass;1178String fname;1179Class<?> ftype;1180Field f = (fieldRef instanceof Field ? (Field)fieldRef : null);1181if (f != null) {1182isStatic = Modifier.isStatic(f.getModifiers());1183fclass = f.getDeclaringClass();1184fname = f.getName();1185ftype = f.getType();1186} else {1187Object[] scnt = (Object[]) fieldRef;1188isStatic = (Boolean) scnt[0];1189fclass = (Class<?>) scnt[1];1190fname = (String) scnt[2];1191ftype = (Class<?>) scnt[3];1192try {1193f = fclass.getDeclaredField(fname);1194} catch (ReflectiveOperationException ex) {1195f = null;1196}1197}1198if (!testModeMatches(testMode, isStatic)) return;1199if (f == null && testMode == TEST_UNREFLECT) return;1200if (testNPE && isStatic) return;1201countTest(positive);1202MethodType expType;1203if (isGetter)1204expType = MethodType.methodType(ftype, HasFields.class);1205else1206expType = MethodType.methodType(void.class, HasFields.class, ftype);1207if (isStatic) expType = expType.dropParameterTypes(0, 1);1208Exception noAccess = null;1209MethodHandle mh;1210try {1211switch (testMode0 & ~(TEST_BOUND | TEST_NPE)) {1212case TEST_UNREFLECT: mh = lookup.unreflectGetter(f); break;1213case TEST_FIND_FIELD: mh = lookup.findGetter(fclass, fname, ftype); break;1214case TEST_FIND_STATIC: mh = lookup.findStaticGetter(fclass, fname, ftype); break;1215case TEST_SETTER|1216TEST_UNREFLECT: mh = lookup.unreflectSetter(f); break;1217case TEST_SETTER|1218TEST_FIND_FIELD: mh = lookup.findSetter(fclass, fname, ftype); break;1219case TEST_SETTER|1220TEST_FIND_STATIC: mh = lookup.findStaticSetter(fclass, fname, ftype); break;1221default:1222throw new InternalError("testMode="+testMode);1223}1224} catch (ReflectiveOperationException ex) {1225mh = null;1226noAccess = ex;1227assertExceptionClass(1228(fname.contains("bogus"))1229? NoSuchFieldException.class1230: IllegalAccessException.class,1231noAccess);1232if (verbosity >= 5) ex.printStackTrace(System.out);1233}1234if (verbosity >= 3)1235System.out.println("find"+(isStatic?"Static":"")+(isGetter?"Getter":"Setter")+" "+fclass.getName()+"."+fname+"/"+ftype1236+" => "+mh1237+(noAccess == null ? "" : " !! "+noAccess));1238if (positive && !testNPE && noAccess != null) throw new RuntimeException(noAccess);1239assertEquals(positive0 ? "positive test" : "negative test erroneously passed", positive0, mh != null);1240if (!positive && !testNPE) return; // negative access test failed as expected1241assertEquals((isStatic ? 0 : 1)+(isGetter ? 0 : 1), mh.type().parameterCount());124212431244assertSame(mh.type(), expType);1245//assertNameStringContains(mh, fname); // This does not hold anymore with LFs1246HasFields fields = new HasFields();1247HasFields fieldsForMH = fields;1248if (testNPE) fieldsForMH = null; // perturb MH argument to elicit expected error1249if (doBound)1250mh = mh.bindTo(fieldsForMH);1251Object sawValue;1252Class<?> vtype = ftype;1253if (ftype != int.class) vtype = Object.class;1254if (isGetter) {1255mh = mh.asType(mh.type().generic()1256.changeReturnType(vtype));1257} else {1258int last = mh.type().parameterCount() - 1;1259mh = mh.asType(mh.type().generic()1260.changeReturnType(void.class)1261.changeParameterType(last, vtype));1262}1263if (f != null && f.getDeclaringClass() == HasFields.class) {1264assertEquals(f.get(fields), value); // clean to start with1265}1266Throwable caughtEx = null;1267if (isGetter) {1268Object expValue = value;1269for (int i = 0; i <= 1; i++) {1270sawValue = null; // make DA rules happy under try/catch1271try {1272if (isStatic || doBound) {1273if (ftype == int.class)1274sawValue = (int) mh.invokeExact(); // do these exactly1275else1276sawValue = mh.invokeExact();1277} else {1278if (ftype == int.class)1279sawValue = (int) mh.invokeExact((Object) fieldsForMH);1280else1281sawValue = mh.invokeExact((Object) fieldsForMH);1282}1283} catch (RuntimeException ex) {1284if (ex instanceof NullPointerException && testNPE) {1285caughtEx = ex;1286break;1287}1288}1289assertEquals(sawValue, expValue);1290if (f != null && f.getDeclaringClass() == HasFields.class1291&& !Modifier.isFinal(f.getModifiers())) {1292Object random = randomArg(ftype);1293f.set(fields, random);1294expValue = random;1295} else {1296break;1297}1298}1299} else {1300for (int i = 0; i <= 1; i++) {1301Object putValue = randomArg(ftype);1302try {1303if (isStatic || doBound) {1304if (ftype == int.class)1305mh.invokeExact((int)putValue); // do these exactly1306else1307mh.invokeExact(putValue);1308} else {1309if (ftype == int.class)1310mh.invokeExact((Object) fieldsForMH, (int)putValue);1311else1312mh.invokeExact((Object) fieldsForMH, putValue);1313}1314} catch (RuntimeException ex) {1315if (ex instanceof NullPointerException && testNPE) {1316caughtEx = ex;1317break;1318}1319}1320if (f != null && f.getDeclaringClass() == HasFields.class) {1321assertEquals(f.get(fields), putValue);1322}1323}1324}1325if (f != null && f.getDeclaringClass() == HasFields.class) {1326f.set(fields, value); // put it back1327}1328if (testNPE) {1329if (caughtEx == null || !(caughtEx instanceof NullPointerException))1330throw new RuntimeException("failed to catch NPE exception"+(caughtEx == null ? " (caughtEx=null)" : ""), caughtEx);1331caughtEx = null; // nullify expected exception1332}1333if (caughtEx != null) {1334throw new RuntimeException("unexpected exception", caughtEx);1335}1336}13371338@Test1339public void testUnreflectSetter() throws Throwable {1340CodeCacheOverflowProcessor.runMHTest(this::testUnreflectSetter0);1341}13421343public void testUnreflectSetter0() throws Throwable {1344if (CAN_SKIP_WORKING) return;1345startTest("unreflectSetter");1346testSetter(TEST_UNREFLECT);1347}13481349@Test1350public void testFindSetter() throws Throwable {1351CodeCacheOverflowProcessor.runMHTest(this::testFindSetter0);1352}13531354public void testFindSetter0() throws Throwable {1355if (CAN_SKIP_WORKING) return;1356startTest("findSetter");1357testSetter(TEST_FIND_FIELD);1358testSetter(TEST_FIND_FIELD | TEST_BOUND);1359}13601361@Test1362public void testFindStaticSetter() throws Throwable {1363CodeCacheOverflowProcessor.runMHTest(this::testFindStaticSetter0);1364}13651366public void testFindStaticSetter0() throws Throwable {1367if (CAN_SKIP_WORKING) return;1368startTest("findStaticSetter");1369testSetter(TEST_FIND_STATIC);1370}13711372public void testSetter(int testMode) throws Throwable {1373Lookup lookup = PRIVATE; // FIXME: test more lookups than this one1374startTest("unreflectSetter");1375for (Object[] c : HasFields.CASES) {1376boolean positive = (c[1] != Error.class);1377testSetter(positive, lookup, c[0], c[1], testMode);1378if (positive)1379testSetter(positive, lookup, c[0], c[1], testMode | TEST_NPE);1380}1381for (int isStaticN = 0; isStaticN <= 1; isStaticN++) {1382testSetter(false, lookup,1383new Object[]{ (isStaticN != 0), System.class, "bogus", char.class },1384null, testMode);1385}1386}1387public void testSetter(boolean positive, MethodHandles.Lookup lookup,1388Object fieldRef, Object value, int testMode) throws Throwable {1389testAccessor(positive, lookup, fieldRef, value, testMode | TEST_SETTER);1390}13911392@Test1393public void testArrayElementGetter() throws Throwable {1394CodeCacheOverflowProcessor.runMHTest(this::testArrayElementGetter0);1395}13961397public void testArrayElementGetter0() throws Throwable {1398if (CAN_SKIP_WORKING) return;1399startTest("arrayElementGetter");1400testArrayElementGetterSetter(false);1401}14021403@Test1404public void testArrayElementSetter() throws Throwable {1405CodeCacheOverflowProcessor.runMHTest(this::testArrayElementSetter0);1406}14071408public void testArrayElementSetter0() throws Throwable {1409if (CAN_SKIP_WORKING) return;1410startTest("arrayElementSetter");1411testArrayElementGetterSetter(true);1412}14131414private static final int TEST_ARRAY_NONE = 0, TEST_ARRAY_NPE = 1, TEST_ARRAY_OOB = 2, TEST_ARRAY_ASE = 3;14151416public void testArrayElementGetterSetter(boolean testSetter) throws Throwable {1417testArrayElementGetterSetter(testSetter, TEST_ARRAY_NONE);1418}14191420@Test1421public void testArrayElementErrors() throws Throwable {1422CodeCacheOverflowProcessor.runMHTest(this::testArrayElementErrors0);1423}14241425public void testArrayElementErrors0() throws Throwable {1426if (CAN_SKIP_WORKING) return;1427startTest("arrayElementErrors");1428testArrayElementGetterSetter(false, TEST_ARRAY_NPE);1429testArrayElementGetterSetter(true, TEST_ARRAY_NPE);1430testArrayElementGetterSetter(false, TEST_ARRAY_OOB);1431testArrayElementGetterSetter(true, TEST_ARRAY_OOB);1432testArrayElementGetterSetter(new Object[10], true, TEST_ARRAY_ASE);1433testArrayElementGetterSetter(new Example[10], true, TEST_ARRAY_ASE);1434testArrayElementGetterSetter(new IntExample[10], true, TEST_ARRAY_ASE);1435}14361437public void testArrayElementGetterSetter(boolean testSetter, int negTest) throws Throwable {1438testArrayElementGetterSetter(new String[10], testSetter, negTest);1439testArrayElementGetterSetter(new Iterable<?>[10], testSetter, negTest);1440testArrayElementGetterSetter(new Example[10], testSetter, negTest);1441testArrayElementGetterSetter(new IntExample[10], testSetter, negTest);1442testArrayElementGetterSetter(new Object[10], testSetter, negTest);1443testArrayElementGetterSetter(new boolean[10], testSetter, negTest);1444testArrayElementGetterSetter(new byte[10], testSetter, negTest);1445testArrayElementGetterSetter(new char[10], testSetter, negTest);1446testArrayElementGetterSetter(new short[10], testSetter, negTest);1447testArrayElementGetterSetter(new int[10], testSetter, negTest);1448testArrayElementGetterSetter(new float[10], testSetter, negTest);1449testArrayElementGetterSetter(new long[10], testSetter, negTest);1450testArrayElementGetterSetter(new double[10], testSetter, negTest);1451}14521453public void testArrayElementGetterSetter(Object array, boolean testSetter, int negTest) throws Throwable {1454boolean positive = (negTest == TEST_ARRAY_NONE);1455int length = java.lang.reflect.Array.getLength(array);1456Class<?> arrayType = array.getClass();1457Class<?> elemType = arrayType.getComponentType();1458Object arrayToMH = array;1459// this stanza allows negative tests to make argument perturbations:1460switch (negTest) {1461case TEST_ARRAY_NPE:1462arrayToMH = null;1463break;1464case TEST_ARRAY_OOB:1465assert(length > 0);1466arrayToMH = java.lang.reflect.Array.newInstance(elemType, 0);1467break;1468case TEST_ARRAY_ASE:1469assert(testSetter && !elemType.isPrimitive());1470if (elemType == Object.class)1471arrayToMH = new StringBuffer[length]; // very random subclass of Object!1472else if (elemType == Example.class)1473arrayToMH = new SubExample[length];1474else if (elemType == IntExample.class)1475arrayToMH = new SubIntExample[length];1476else1477return; // can't make an ArrayStoreException test1478assert(arrayType.isInstance(arrayToMH))1479: Arrays.asList(arrayType, arrayToMH.getClass(), testSetter, negTest);1480break;1481}1482countTest(positive);1483if (verbosity > 2) System.out.println("array type = "+array.getClass().getComponentType().getName()+"["+length+"]"+(positive ? "" : " negative test #"+negTest+" using "+Arrays.deepToString(new Object[]{arrayToMH})));1484MethodType expType = !testSetter1485? MethodType.methodType(elemType, arrayType, int.class)1486: MethodType.methodType(void.class, arrayType, int.class, elemType);1487MethodHandle mh = !testSetter1488? MethodHandles.arrayElementGetter(arrayType)1489: MethodHandles.arrayElementSetter(arrayType);1490assertSame(mh.type(), expType);1491if (elemType != int.class && elemType != boolean.class) {1492MethodType gtype = mh.type().generic().changeParameterType(1, int.class);1493if (testSetter) gtype = gtype.changeReturnType(void.class);1494mh = mh.asType(gtype);1495}1496Object sawValue, expValue;1497List<Object> model = array2list(array);1498Throwable caughtEx = null;1499for (int i = 0; i < length; i++) {1500// update array element1501Object random = randomArg(elemType);1502model.set(i, random);1503if (testSetter) {1504try {1505if (elemType == int.class)1506mh.invokeExact((int[]) arrayToMH, i, (int)random);1507else if (elemType == boolean.class)1508mh.invokeExact((boolean[]) arrayToMH, i, (boolean)random);1509else1510mh.invokeExact(arrayToMH, i, random);1511} catch (RuntimeException ex) {1512caughtEx = ex;1513break;1514}1515assertEquals(model, array2list(array));1516} else {1517Array.set(array, i, random);1518}1519if (verbosity >= 5) {1520List<Object> array2list = array2list(array);1521System.out.println("a["+i+"]="+random+" => "+array2list);1522if (!array2list.equals(model))1523System.out.println("*** != "+model);1524}1525// observe array element1526sawValue = Array.get(array, i);1527if (!testSetter) {1528expValue = sawValue;1529try {1530if (elemType == int.class)1531sawValue = (int) mh.invokeExact((int[]) arrayToMH, i);1532else if (elemType == boolean.class)1533sawValue = (boolean) mh.invokeExact((boolean[]) arrayToMH, i);1534else1535sawValue = mh.invokeExact(arrayToMH, i);1536} catch (RuntimeException ex) {1537caughtEx = ex;1538break;1539}1540assertEquals(sawValue, expValue);1541assertEquals(model, array2list(array));1542}1543}1544if (!positive) {1545if (caughtEx == null)1546throw new RuntimeException("failed to catch exception for negTest="+negTest);1547// test the kind of exception1548Class<?> reqType = null;1549switch (negTest) {1550case TEST_ARRAY_ASE: reqType = ArrayStoreException.class; break;1551case TEST_ARRAY_OOB: reqType = ArrayIndexOutOfBoundsException.class; break;1552case TEST_ARRAY_NPE: reqType = NullPointerException.class; break;1553default: assert(false);1554}1555if (reqType.isInstance(caughtEx)) {1556caughtEx = null; // nullify expected exception1557}1558}1559if (caughtEx != null) {1560throw new RuntimeException("unexpected exception", caughtEx);1561}1562}15631564List<Object> array2list(Object array) {1565int length = Array.getLength(array);1566ArrayList<Object> model = new ArrayList<>(length);1567for (int i = 0; i < length; i++)1568model.add(Array.get(array, i));1569return model;1570}15711572static class Callee {1573static Object id() { return called("id"); }1574static Object id(Object x) { return called("id", x); }1575static Object id(Object x, Object y) { return called("id", x, y); }1576static Object id(Object x, Object y, Object z) { return called("id", x, y, z); }1577static Object id(Object... vx) { return called("id", vx); }1578static MethodHandle ofType(int n) {1579return ofType(Object.class, n);1580}1581static MethodHandle ofType(Class<?> rtype, int n) {1582if (n == -1)1583return ofType(MethodType.methodType(rtype, Object[].class));1584return ofType(MethodType.genericMethodType(n).changeReturnType(rtype));1585}1586static MethodHandle ofType(Class<?> rtype, Class<?>... ptypes) {1587return ofType(MethodType.methodType(rtype, ptypes));1588}1589static MethodHandle ofType(MethodType type) {1590Class<?> rtype = type.returnType();1591String pfx = "";1592if (rtype != Object.class)1593pfx = rtype.getSimpleName().substring(0, 1).toLowerCase();1594String name = pfx+"id";1595try {1596return PRIVATE.findStatic(Callee.class, name, type);1597} catch (NoSuchMethodException | IllegalAccessException ex) {1598throw new RuntimeException(ex);1599}1600}1601}16021603@Test1604public void testConvertArguments() throws Throwable {1605CodeCacheOverflowProcessor.runMHTest(this::testConvertArguments0);1606}16071608public void testConvertArguments0() throws Throwable {1609if (CAN_SKIP_WORKING) return;1610startTest("convertArguments");1611testConvert(Callee.ofType(1), null, "id", int.class);1612testConvert(Callee.ofType(1), null, "id", String.class);1613testConvert(Callee.ofType(1), null, "id", Integer.class);1614testConvert(Callee.ofType(1), null, "id", short.class);1615testConvert(Callee.ofType(1), null, "id", char.class);1616testConvert(Callee.ofType(1), null, "id", byte.class);1617}16181619void testConvert(MethodHandle id, Class<?> rtype, String name, Class<?>... params) throws Throwable {1620testConvert(true, id, rtype, name, params);1621}16221623void testConvert(boolean positive,1624MethodHandle id, Class<?> rtype, String name, Class<?>... params) throws Throwable {1625countTest(positive);1626MethodType idType = id.type();1627if (rtype == null) rtype = idType.returnType();1628for (int i = 0; i < params.length; i++) {1629if (params[i] == null) params[i] = idType.parameterType(i);1630}1631// simulate the pairwise conversion1632MethodType newType = MethodType.methodType(rtype, params);1633Object[] args = randomArgs(newType.parameterArray());1634Object[] convArgs = args.clone();1635for (int i = 0; i < args.length; i++) {1636Class<?> src = newType.parameterType(i);1637Class<?> dst = idType.parameterType(i);1638if (src != dst)1639convArgs[i] = castToWrapper(convArgs[i], dst);1640}1641Object convResult = id.invokeWithArguments(convArgs);1642{1643Class<?> dst = newType.returnType();1644Class<?> src = idType.returnType();1645if (src != dst)1646convResult = castToWrapper(convResult, dst);1647}1648MethodHandle target = null;1649RuntimeException error = null;1650try {1651target = id.asType(newType);1652} catch (WrongMethodTypeException ex) {1653error = ex;1654}1655if (verbosity >= 3)1656System.out.println("convert "+id+ " to "+newType+" => "+target1657+(error == null ? "" : " !! "+error));1658if (positive && error != null) throw error;1659assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null);1660if (!positive) return; // negative test failed as expected1661assertEquals(newType, target.type());1662printCalled(target, id.toString(), args);1663Object result = target.invokeWithArguments(args);1664assertCalled(name, convArgs);1665assertEquals(convResult, result);1666if (verbosity >= 1)1667System.out.print(':');1668}16691670@Test1671public void testVarargsCollector() throws Throwable {1672CodeCacheOverflowProcessor.runMHTest(this::testVarargsCollector0);1673}16741675public void testVarargsCollector0() throws Throwable {1676if (CAN_SKIP_WORKING) return;1677startTest("varargsCollector");1678MethodHandle vac0 = PRIVATE.findStatic(MethodHandlesTest.class, "called",1679MethodType.methodType(Object.class, String.class, Object[].class));1680vac0 = vac0.bindTo("vac");1681MethodHandle vac = vac0.asVarargsCollector(Object[].class);1682testConvert(true, vac.asType(MethodType.genericMethodType(0)), null, "vac");1683testConvert(true, vac.asType(MethodType.genericMethodType(0)), null, "vac");1684for (Class<?> at : new Class<?>[] { Object.class, String.class, Integer.class }) {1685testConvert(true, vac.asType(MethodType.genericMethodType(1)), null, "vac", at);1686testConvert(true, vac.asType(MethodType.genericMethodType(2)), null, "vac", at, at);1687}1688}16891690@Test // SLOW1691public void testPermuteArguments() throws Throwable {1692CodeCacheOverflowProcessor.runMHTest(this::testPermuteArguments0);1693}16941695public void testPermuteArguments0() throws Throwable {1696if (CAN_SKIP_WORKING) return;1697startTest("permuteArguments");1698testPermuteArguments(4, Integer.class, 2, long.class, 6);1699if (CAN_TEST_LIGHTLY) return;1700testPermuteArguments(4, Integer.class, 2, String.class, 0);1701testPermuteArguments(6, Integer.class, 0, null, 30);1702}1703public void testPermuteArguments(int max, Class<?> type1, int t2c, Class<?> type2, int dilution) throws Throwable {1704if (verbosity >= 2)1705System.out.println("permuteArguments "+max+"*"+type1.getName()1706+(t2c==0?"":"/"+t2c+"*"+type2.getName())1707+(dilution > 0 ? " with dilution "+dilution : ""));1708int t2pos = t2c == 0 ? 0 : 1;1709for (int inargs = t2pos+1; inargs <= max; inargs++) {1710Class<?>[] types = new Class<?>[inargs];1711Arrays.fill(types, type1);1712if (t2c != 0) {1713// Fill in a middle range with type2:1714Arrays.fill(types, t2pos, Math.min(t2pos+t2c, inargs), type2);1715}1716Object[] args = randomArgs(types);1717int numcases = 1;1718for (int outargs = 0; outargs <= max; outargs++) {1719if (outargs - inargs >= MAX_ARG_INCREASE) continue;1720int casStep = dilution + 1;1721// Avoid some common factors:1722while ((casStep > 2 && casStep % 2 == 0 && inargs % 2 == 0) ||1723(casStep > 3 && casStep % 3 == 0 && inargs % 3 == 0))1724casStep++;1725testPermuteArguments(args, types, outargs, numcases, casStep);1726numcases *= inargs;1727if (CAN_TEST_LIGHTLY && outargs < max-2) continue;1728if (dilution > 10 && outargs >= 4) {1729if (CAN_TEST_LIGHTLY) continue;1730int[] reorder = new int[outargs];1731// Do some special patterns, which we probably missed.1732// Replication of a single argument or argument pair.1733for (int i = 0; i < inargs; i++) {1734Arrays.fill(reorder, i);1735testPermuteArguments(args, types, reorder);1736for (int d = 1; d <= 2; d++) {1737if (i + d >= inargs) continue;1738for (int j = 1; j < outargs; j += 2)1739reorder[j] += 1;1740testPermuteArguments(args, types, reorder);1741testPermuteArguments(args, types, reverse(reorder));1742}1743}1744// Repetition of a sequence of 3 or more arguments.1745for (int i = 1; i < inargs; i++) {1746for (int len = 3; len <= inargs; len++) {1747for (int j = 0; j < outargs; j++)1748reorder[j] = (i + (j % len)) % inargs;1749testPermuteArguments(args, types, reorder);1750testPermuteArguments(args, types, reverse(reorder));1751}1752}1753}1754}1755}1756}17571758public void testPermuteArguments(Object[] args, Class<?>[] types,1759int outargs, int numcases, int casStep) throws Throwable {1760int inargs = args.length;1761int[] reorder = new int[outargs];1762for (int cas = 0; cas < numcases; cas += casStep) {1763for (int i = 0, c = cas; i < outargs; i++) {1764reorder[i] = c % inargs;1765c /= inargs;1766}1767if (CAN_TEST_LIGHTLY && outargs >= 3 && (reorder[0] == reorder[1] || reorder[1] == reorder[2])) continue;1768testPermuteArguments(args, types, reorder);1769}1770}17711772static int[] reverse(int[] reorder) {1773reorder = reorder.clone();1774for (int i = 0, imax = reorder.length / 2; i < imax; i++) {1775int j = reorder.length - 1 - i;1776int tem = reorder[i];1777reorder[i] = reorder[j];1778reorder[j] = tem;1779}1780return reorder;1781}17821783void testPermuteArguments(Object[] args, Class<?>[] types, int[] reorder) throws Throwable {1784countTest();1785if (args == null && types == null) {1786int max = 0;1787for (int j : reorder) {1788if (max < j) max = j;1789}1790args = randomArgs(max+1, Integer.class);1791}1792if (args == null) {1793args = randomArgs(types);1794}1795if (types == null) {1796types = new Class<?>[args.length];1797for (int i = 0; i < args.length; i++)1798types[i] = args[i].getClass();1799}1800int inargs = args.length, outargs = reorder.length;1801assertTrue(inargs == types.length);1802if (verbosity >= 3)1803System.out.println("permuteArguments "+Arrays.toString(reorder));1804Object[] permArgs = new Object[outargs];1805Class<?>[] permTypes = new Class<?>[outargs];1806for (int i = 0; i < outargs; i++) {1807permArgs[i] = args[reorder[i]];1808permTypes[i] = types[reorder[i]];1809}1810if (verbosity >= 4) {1811System.out.println("in args: "+Arrays.asList(args));1812System.out.println("out args: "+Arrays.asList(permArgs));1813System.out.println("in types: "+Arrays.asList(types));1814System.out.println("out types: "+Arrays.asList(permTypes));1815}1816MethodType inType = MethodType.methodType(Object.class, types);1817MethodType outType = MethodType.methodType(Object.class, permTypes);1818MethodHandle target = varargsList(outargs).asType(outType);1819MethodHandle newTarget = MethodHandles.permuteArguments(target, inType, reorder);1820if (verbosity >= 5) System.out.println("newTarget = "+newTarget);1821Object result = newTarget.invokeWithArguments(args);1822Object expected = Arrays.asList(permArgs);1823if (!expected.equals(result)) {1824System.out.println("*** failed permuteArguments "+Arrays.toString(reorder)+" types="+Arrays.asList(types));1825System.out.println("in args: "+Arrays.asList(args));1826System.out.println("out args: "+expected);1827System.out.println("bad args: "+result);1828}1829assertEquals(expected, result);1830}183118321833@Test // SLOW1834public void testSpreadArguments() throws Throwable {1835CodeCacheOverflowProcessor.runMHTest(this::testSpreadArguments0);1836}18371838public void testSpreadArguments0() throws Throwable {1839if (CAN_SKIP_WORKING) return;1840startTest("spreadArguments");1841for (Class<?> argType : new Class<?>[]{Object.class, Integer.class, int.class}) {1842if (verbosity >= 3)1843System.out.println("spreadArguments "+argType);1844for (int nargs = 0; nargs < 50; nargs++) {1845if (CAN_TEST_LIGHTLY && nargs > 11) break;1846for (int pos = 0; pos <= nargs; pos++) {1847if (CAN_TEST_LIGHTLY && pos > 2 && pos < nargs-2) continue;1848if (nargs > 10 && pos > 4 && pos < nargs-4 && pos % 10 != 3)1849continue;1850testSpreadArguments(argType, pos, nargs);1851}1852}1853}1854}1855public void testSpreadArguments(Class<?> argType, int pos, int nargs) throws Throwable {1856countTest();1857Class<?> arrayType = java.lang.reflect.Array.newInstance(argType, 0).getClass();1858MethodHandle target2 = varargsArray(arrayType, nargs);1859MethodHandle target = target2.asType(target2.type().generic());1860if (verbosity >= 3)1861System.out.println("spread into "+target2+" ["+pos+".."+nargs+"]");1862Object[] args = randomArgs(target2.type().parameterArray());1863// make sure the target does what we think it does:1864if (pos == 0 && nargs < 5 && !argType.isPrimitive()) {1865Object[] check = (Object[]) target.invokeWithArguments(args);1866assertArrayEquals(args, check);1867switch (nargs) {1868case 0:1869check = (Object[]) (Object) target.invokeExact();1870assertArrayEquals(args, check);1871break;1872case 1:1873check = (Object[]) (Object) target.invokeExact(args[0]);1874assertArrayEquals(args, check);1875break;1876case 2:1877check = (Object[]) (Object) target.invokeExact(args[0], args[1]);1878assertArrayEquals(args, check);1879break;1880}1881}1882List<Class<?>> newParams = new ArrayList<>(target2.type().parameterList());1883{ // modify newParams in place1884List<Class<?>> spreadParams = newParams.subList(pos, nargs);1885spreadParams.clear(); spreadParams.add(arrayType);1886}1887MethodType newType = MethodType.methodType(arrayType, newParams);1888MethodHandle result = target2.asSpreader(arrayType, nargs-pos);1889assert(result.type() == newType) : Arrays.asList(result, newType);1890result = result.asType(newType.generic());1891Object returnValue;1892if (pos == 0) {1893Object args2 = ValueConversions.changeArrayType(arrayType, Arrays.copyOfRange(args, pos, args.length));1894returnValue = result.invokeExact(args2);1895} else {1896Object[] args1 = Arrays.copyOfRange(args, 0, pos+1);1897args1[pos] = ValueConversions.changeArrayType(arrayType, Arrays.copyOfRange(args, pos, args.length));1898returnValue = result.invokeWithArguments(args1);1899}1900String argstr = Arrays.toString(args);1901if (!argType.isPrimitive()) {1902Object[] rv = (Object[]) returnValue;1903String rvs = Arrays.toString(rv);1904if (!Arrays.equals(args, rv)) {1905System.out.println("method: "+result);1906System.out.println("expected: "+argstr);1907System.out.println("returned: "+rvs);1908assertArrayEquals(args, rv);1909}1910} else if (argType == int.class) {1911String rvs = Arrays.toString((int[]) returnValue);1912if (!argstr.equals(rvs)) {1913System.out.println("method: "+result);1914System.out.println("expected: "+argstr);1915System.out.println("returned: "+rvs);1916assertEquals(argstr, rvs);1917}1918} else if (argType == long.class) {1919String rvs = Arrays.toString((long[]) returnValue);1920if (!argstr.equals(rvs)) {1921System.out.println("method: "+result);1922System.out.println("expected: "+argstr);1923System.out.println("returned: "+rvs);1924assertEquals(argstr, rvs);1925}1926} else {1927// cannot test...1928}1929}19301931@Test // SLOW1932public void testAsCollector() throws Throwable {1933CodeCacheOverflowProcessor.runMHTest(this::testAsCollector0);1934}19351936public void testAsCollector0() throws Throwable {1937if (CAN_SKIP_WORKING) return;1938startTest("asCollector");1939for (Class<?> argType : new Class<?>[]{Object.class, Integer.class, int.class}) {1940if (verbosity >= 3)1941System.out.println("asCollector "+argType);1942for (int nargs = 0; nargs < 50; nargs++) {1943if (CAN_TEST_LIGHTLY && nargs > 11) break;1944for (int pos = 0; pos <= nargs; pos++) {1945if (CAN_TEST_LIGHTLY && pos > 2 && pos < nargs-2) continue;1946if (nargs > 10 && pos > 4 && pos < nargs-4 && pos % 10 != 3)1947continue;1948testAsCollector(argType, pos, nargs);1949}1950}1951}1952}1953public void testAsCollector(Class<?> argType, int pos, int nargs) throws Throwable {1954countTest();1955// fake up a MH with the same type as the desired adapter:1956MethodHandle fake = varargsArray(nargs);1957fake = changeArgTypes(fake, argType);1958MethodType newType = fake.type();1959Object[] args = randomArgs(newType.parameterArray());1960// here is what should happen:1961Object[] collectedArgs = Arrays.copyOfRange(args, 0, pos+1);1962collectedArgs[pos] = Arrays.copyOfRange(args, pos, args.length);1963// here is the MH which will witness the collected argument tail:1964MethodHandle target = varargsArray(pos+1);1965target = changeArgTypes(target, 0, pos, argType);1966target = changeArgTypes(target, pos, pos+1, Object[].class);1967if (verbosity >= 3)1968System.out.println("collect from "+Arrays.asList(args)+" ["+pos+".."+nargs+"]");1969MethodHandle result = target.asCollector(Object[].class, nargs-pos).asType(newType);1970Object[] returnValue = (Object[]) result.invokeWithArguments(args);1971// assertTrue(returnValue.length == pos+1 && returnValue[pos] instanceof Object[]);1972// returnValue[pos] = Arrays.asList((Object[]) returnValue[pos]);1973// collectedArgs[pos] = Arrays.asList((Object[]) collectedArgs[pos]);1974assertArrayEquals(collectedArgs, returnValue);1975}19761977@Test // SLOW1978public void testInsertArguments() throws Throwable {1979CodeCacheOverflowProcessor.runMHTest(this::testInsertArguments0);1980}19811982public void testInsertArguments0() throws Throwable {1983if (CAN_SKIP_WORKING) return;1984startTest("insertArguments");1985for (int nargs = 0; nargs < 50; nargs++) {1986if (CAN_TEST_LIGHTLY && nargs > 11) break;1987for (int ins = 0; ins <= nargs; ins++) {1988if (nargs > 10 && ins > 4 && ins < nargs-4 && ins % 10 != 3)1989continue;1990for (int pos = 0; pos <= nargs; pos++) {1991if (nargs > 10 && pos > 4 && pos < nargs-4 && pos % 10 != 3)1992continue;1993if (CAN_TEST_LIGHTLY && pos > 2 && pos < nargs-2) continue;1994testInsertArguments(nargs, pos, ins);1995}1996}1997}1998}19992000void testInsertArguments(int nargs, int pos, int ins) throws Throwable {2001countTest();2002MethodHandle target = varargsArray(nargs + ins);2003Object[] args = randomArgs(target.type().parameterArray());2004List<Object> resList = Arrays.asList(args);2005List<Object> argsToPass = new ArrayList<>(resList);2006List<Object> argsToInsert = argsToPass.subList(pos, pos + ins);2007if (verbosity >= 3)2008System.out.println("insert: "+argsToInsert+" @"+pos+" into "+target);2009@SuppressWarnings("cast") // cast to spread Object... is helpful2010MethodHandle target2 = MethodHandles.insertArguments(target, pos,2011(Object[]/*...*/) argsToInsert.toArray());2012argsToInsert.clear(); // remove from argsToInsert2013Object res2 = target2.invokeWithArguments(argsToPass);2014Object res2List = Arrays.asList((Object[])res2);2015if (verbosity >= 3)2016System.out.println("result: "+res2List);2017//if (!resList.equals(res2List))2018// System.out.println("*** fail at n/p/i = "+nargs+"/"+pos+"/"+ins+": "+resList+" => "+res2List);2019assertEquals(resList, res2List);2020}20212022@Test2023public void testFilterReturnValue() throws Throwable {2024CodeCacheOverflowProcessor.runMHTest(this::testFilterReturnValue0);2025}20262027public void testFilterReturnValue0() throws Throwable {2028if (CAN_SKIP_WORKING) return;2029startTest("filterReturnValue");2030Class<?> classOfVCList = varargsList(1).invokeWithArguments(0).getClass();2031assertTrue(List.class.isAssignableFrom(classOfVCList));2032for (int nargs = 0; nargs <= 3; nargs++) {2033for (Class<?> rtype : new Class<?>[] { Object.class,2034List.class,2035int.class,2036byte.class,2037long.class,2038CharSequence.class,2039String.class }) {2040testFilterReturnValue(nargs, rtype);2041}2042}2043}20442045void testFilterReturnValue(int nargs, Class<?> rtype) throws Throwable {2046countTest();2047MethodHandle target = varargsList(nargs, rtype);2048MethodHandle filter;2049if (List.class.isAssignableFrom(rtype) || rtype.isAssignableFrom(List.class))2050filter = varargsList(1); // add another layer of list-ness2051else2052filter = MethodHandles.identity(rtype);2053filter = filter.asType(MethodType.methodType(target.type().returnType(), rtype));2054Object[] argsToPass = randomArgs(nargs, Object.class);2055if (verbosity >= 3)2056System.out.println("filter "+target+" to "+rtype.getSimpleName()+" with "+filter);2057MethodHandle target2 = MethodHandles.filterReturnValue(target, filter);2058if (verbosity >= 4)2059System.out.println("filtered target: "+target2);2060// Simulate expected effect of filter on return value:2061Object unfiltered = target.invokeWithArguments(argsToPass);2062Object expected = filter.invokeWithArguments(unfiltered);2063if (verbosity >= 4)2064System.out.println("unfiltered: "+unfiltered+" : "+unfiltered.getClass().getSimpleName());2065if (verbosity >= 4)2066System.out.println("expected: "+expected+" : "+expected.getClass().getSimpleName());2067Object result = target2.invokeWithArguments(argsToPass);2068if (verbosity >= 3)2069System.out.println("result: "+result+" : "+result.getClass().getSimpleName());2070if (!expected.equals(result))2071System.out.println("*** fail at n/rt = "+nargs+"/"+rtype.getSimpleName()+": "+Arrays.asList(argsToPass)+" => "+result+" != "+expected);2072assertEquals(expected, result);2073}20742075@Test2076public void testFilterArguments() throws Throwable {2077CodeCacheOverflowProcessor.runMHTest(this::testFilterArguments0);2078}20792080public void testFilterArguments0() throws Throwable {2081if (CAN_SKIP_WORKING) return;2082startTest("filterArguments");2083for (int nargs = 1; nargs <= 6; nargs++) {2084for (int pos = 0; pos < nargs; pos++) {2085testFilterArguments(nargs, pos);2086}2087}2088}20892090void testFilterArguments(int nargs, int pos) throws Throwable {2091countTest();2092MethodHandle target = varargsList(nargs);2093MethodHandle filter = varargsList(1);2094filter = filter.asType(filter.type().generic());2095Object[] argsToPass = randomArgs(nargs, Object.class);2096if (verbosity >= 3)2097System.out.println("filter "+target+" at "+pos+" with "+filter);2098MethodHandle target2 = MethodHandles.filterArguments(target, pos, filter);2099// Simulate expected effect of filter on arglist:2100Object[] filteredArgs = argsToPass.clone();2101filteredArgs[pos] = filter.invokeExact(filteredArgs[pos]);2102List<Object> expected = Arrays.asList(filteredArgs);2103Object result = target2.invokeWithArguments(argsToPass);2104if (verbosity >= 3)2105System.out.println("result: "+result);2106if (!expected.equals(result))2107System.out.println("*** fail at n/p = "+nargs+"/"+pos+": "+Arrays.asList(argsToPass)+" => "+result+" != "+expected);2108assertEquals(expected, result);2109}21102111@Test2112public void testCollectArguments() throws Throwable {2113CodeCacheOverflowProcessor.runMHTest(this::testCollectArguments0);2114}21152116public void testCollectArguments0() throws Throwable {2117if (CAN_SKIP_WORKING) return;2118startTest("collectArguments");2119testFoldOrCollectArguments(true);2120}21212122@Test2123public void testFoldArguments() throws Throwable {2124CodeCacheOverflowProcessor.runMHTest(this::testFoldArguments0);2125}21262127public void testFoldArguments0() throws Throwable {2128if (CAN_SKIP_WORKING) return;2129startTest("foldArguments");2130testFoldOrCollectArguments(false);2131}21322133void testFoldOrCollectArguments(boolean isCollect) throws Throwable {2134for (Class<?> lastType : new Class<?>[]{ Object.class, String.class, int.class }) {2135for (Class<?> collectType : new Class<?>[]{ Object.class, String.class, int.class, void.class }) {2136int maxArity = 10;2137if (collectType != String.class) maxArity = 5;2138if (lastType != Object.class) maxArity = 4;2139for (int nargs = 0; nargs <= maxArity; nargs++) {2140ArrayList<Class<?>> argTypes = new ArrayList<>(Collections.nCopies(nargs, Object.class));2141int maxMix = 20;2142if (collectType != Object.class) maxMix = 0;2143Map<Object,Integer> argTypesSeen = new HashMap<>();2144for (int mix = 0; mix <= maxMix; mix++) {2145if (!mixArgs(argTypes, mix, argTypesSeen)) continue;2146for (int collect = 0; collect <= nargs; collect++) {2147for (int pos = 0; pos <= nargs - collect; pos++) {2148testFoldOrCollectArguments(argTypes, pos, collect, collectType, lastType, isCollect);2149}2150}2151}2152}2153}2154}2155}21562157boolean mixArgs(List<Class<?>> argTypes, int mix, Map<Object,Integer> argTypesSeen) {2158assert(mix >= 0);2159if (mix == 0) return true; // no change2160if ((mix >>> argTypes.size()) != 0) return false;2161for (int i = 0; i < argTypes.size(); i++) {2162if (i >= 31) break;2163boolean bit = (mix & (1 << i)) != 0;2164if (bit) {2165Class<?> type = argTypes.get(i);2166if (type == Object.class)2167type = String.class;2168else if (type == String.class)2169type = int.class;2170else2171type = Object.class;2172argTypes.set(i, type);2173}2174}2175Integer prev = argTypesSeen.put(new ArrayList<>(argTypes), mix);2176if (prev != null) {2177if (verbosity >= 4) System.out.println("mix "+prev+" repeated "+mix+": "+argTypes);2178return false;2179}2180if (verbosity >= 3) System.out.println("mix "+mix+" = "+argTypes);2181return true;2182}21832184void testFoldOrCollectArguments(List<Class<?>> argTypes, // argument types minus the inserted combineType2185int pos, int fold, // position and length of the folded arguments2186Class<?> combineType, // type returned from the combiner2187Class<?> lastType, // type returned from the target2188boolean isCollect) throws Throwable {2189int nargs = argTypes.size();2190if (pos != 0 && !isCollect) return; // can fold only at pos=0 for now2191countTest();2192List<Class<?>> combineArgTypes = argTypes.subList(pos, pos + fold);2193List<Class<?>> targetArgTypes = new ArrayList<>(argTypes);2194if (isCollect) // does targret see arg[pos..pos+cc-1]?2195targetArgTypes.subList(pos, pos + fold).clear();2196if (combineType != void.class)2197targetArgTypes.add(pos, combineType);2198MethodHandle target = varargsList(targetArgTypes, lastType);2199MethodHandle combine = varargsList(combineArgTypes, combineType);2200List<Object> argsToPass = Arrays.asList(randomArgs(argTypes));2201if (verbosity >= 3)2202System.out.println((isCollect ? "collect" : "fold")+" "+target+" with "+combine);2203MethodHandle target2;2204if (isCollect)2205target2 = MethodHandles.collectArguments(target, pos, combine);2206else2207target2 = MethodHandles.foldArguments(target, combine);2208// Simulate expected effect of combiner on arglist:2209List<Object> expectedList = new ArrayList<>(argsToPass);2210List<Object> argsToFold = expectedList.subList(pos, pos + fold);2211if (verbosity >= 3)2212System.out.println((isCollect ? "collect" : "fold")+": "+argsToFold+" into "+target2);2213Object foldedArgs = combine.invokeWithArguments(argsToFold);2214if (isCollect)2215argsToFold.clear();2216if (combineType != void.class)2217argsToFold.add(0, foldedArgs);2218Object result = target2.invokeWithArguments(argsToPass);2219if (verbosity >= 3)2220System.out.println("result: "+result);2221Object expected = target.invokeWithArguments(expectedList);2222if (!expected.equals(result))2223System.out.println("*** fail at n/p/f = "+nargs+"/"+pos+"/"+fold+": "+argsToPass+" => "+result+" != "+expected);2224assertEquals(expected, result);2225}22262227@Test2228public void testDropArguments() throws Throwable {2229CodeCacheOverflowProcessor.runMHTest(this::testDropArguments0);2230}22312232public void testDropArguments0() throws Throwable {2233if (CAN_SKIP_WORKING) return;2234startTest("dropArguments");2235for (int nargs = 0; nargs <= 4; nargs++) {2236for (int drop = 1; drop <= 4; drop++) {2237for (int pos = 0; pos <= nargs; pos++) {2238testDropArguments(nargs, pos, drop);2239}2240}2241}2242}22432244void testDropArguments(int nargs, int pos, int drop) throws Throwable {2245countTest();2246MethodHandle target = varargsArray(nargs);2247Object[] args = randomArgs(target.type().parameterArray());2248MethodHandle target2 = MethodHandles.dropArguments(target, pos,2249Collections.nCopies(drop, Object.class).toArray(new Class<?>[0]));2250List<Object> resList = Arrays.asList(args);2251List<Object> argsToDrop = new ArrayList<>(resList);2252for (int i = drop; i > 0; i--) {2253argsToDrop.add(pos, "blort#"+i);2254}2255Object res2 = target2.invokeWithArguments(argsToDrop);2256Object res2List = Arrays.asList((Object[])res2);2257//if (!resList.equals(res2List))2258// System.out.println("*** fail at n/p/d = "+nargs+"/"+pos+"/"+drop+": "+argsToDrop+" => "+res2List);2259assertEquals(resList, res2List);2260}22612262@Test // SLOW2263public void testInvokers() throws Throwable {2264CodeCacheOverflowProcessor.runMHTest(this::testInvokers0);2265}22662267public void testInvokers0() throws Throwable {2268if (CAN_SKIP_WORKING) return;2269startTest("exactInvoker, genericInvoker, varargsInvoker, dynamicInvoker");2270// exactInvoker, genericInvoker, varargsInvoker[0..N], dynamicInvoker2271Set<MethodType> done = new HashSet<>();2272for (int i = 0; i <= 6; i++) {2273if (CAN_TEST_LIGHTLY && i > 3) break;2274MethodType gtype = MethodType.genericMethodType(i);2275for (Class<?> argType : new Class<?>[]{Object.class, Integer.class, int.class}) {2276for (int j = -1; j < i; j++) {2277MethodType type = gtype;2278if (j < 0)2279type = type.changeReturnType(argType);2280else if (argType == void.class)2281continue;2282else2283type = type.changeParameterType(j, argType);2284if (done.add(type))2285testInvokersWithCatch(type);2286MethodType vtype = type.changeReturnType(void.class);2287if (done.add(vtype))2288testInvokersWithCatch(vtype);2289}2290}2291}2292}22932294public void testInvokersWithCatch(MethodType type) throws Throwable {2295try {2296testInvokers(type);2297} catch (Throwable ex) {2298System.out.println("*** testInvokers on "+type+" => ");2299ex.printStackTrace(System.out);2300}2301}2302public void testInvokers(MethodType type) throws Throwable {2303if (verbosity >= 3)2304System.out.println("test invokers for "+type);2305int nargs = type.parameterCount();2306boolean testRetCode = type.returnType() != void.class;2307MethodHandle target = PRIVATE.findStatic(MethodHandlesTest.class, "invokee",2308MethodType.genericMethodType(0, true));2309assertTrue(target.isVarargsCollector());2310target = target.asType(type);2311Object[] args = randomArgs(type.parameterArray());2312List<Object> targetPlusArgs = new ArrayList<>(Arrays.asList(args));2313targetPlusArgs.add(0, target);2314int code = (Integer) invokee(args);2315Object log = logEntry("invokee", args);2316assertEquals(log.hashCode(), code);2317assertCalled("invokee", args);2318MethodHandle inv;2319Object result;2320// exact invoker2321countTest();2322calledLog.clear();2323inv = MethodHandles.exactInvoker(type);2324result = inv.invokeWithArguments(targetPlusArgs);2325if (testRetCode) assertEquals(code, result);2326assertCalled("invokee", args);2327// generic invoker2328countTest();2329inv = MethodHandles.invoker(type);2330if (nargs <= 3 && type == type.generic()) {2331calledLog.clear();2332switch (nargs) {2333case 0:2334result = inv.invokeExact(target);2335break;2336case 1:2337result = inv.invokeExact(target, args[0]);2338break;2339case 2:2340result = inv.invokeExact(target, args[0], args[1]);2341break;2342case 3:2343result = inv.invokeExact(target, args[0], args[1], args[2]);2344break;2345}2346if (testRetCode) assertEquals(code, result);2347assertCalled("invokee", args);2348}2349calledLog.clear();2350result = inv.invokeWithArguments(targetPlusArgs);2351if (testRetCode) assertEquals(code, result);2352assertCalled("invokee", args);2353// varargs invoker #02354calledLog.clear();2355inv = MethodHandles.spreadInvoker(type, 0);2356if (type.returnType() == Object.class) {2357result = inv.invokeExact(target, args);2358} else if (type.returnType() == void.class) {2359result = null; inv.invokeExact(target, args);2360} else {2361result = inv.invokeWithArguments(target, (Object) args);2362}2363if (testRetCode) assertEquals(code, result);2364assertCalled("invokee", args);2365if (nargs >= 1 && type == type.generic()) {2366// varargs invoker #12367calledLog.clear();2368inv = MethodHandles.spreadInvoker(type, 1);2369result = inv.invokeExact(target, args[0], Arrays.copyOfRange(args, 1, nargs));2370if (testRetCode) assertEquals(code, result);2371assertCalled("invokee", args);2372}2373if (nargs >= 2 && type == type.generic()) {2374// varargs invoker #22375calledLog.clear();2376inv = MethodHandles.spreadInvoker(type, 2);2377result = inv.invokeExact(target, args[0], args[1], Arrays.copyOfRange(args, 2, nargs));2378if (testRetCode) assertEquals(code, result);2379assertCalled("invokee", args);2380}2381if (nargs >= 3 && type == type.generic()) {2382// varargs invoker #32383calledLog.clear();2384inv = MethodHandles.spreadInvoker(type, 3);2385result = inv.invokeExact(target, args[0], args[1], args[2], Arrays.copyOfRange(args, 3, nargs));2386if (testRetCode) assertEquals(code, result);2387assertCalled("invokee", args);2388}2389for (int k = 0; k <= nargs; k++) {2390// varargs invoker #0..N2391if (CAN_TEST_LIGHTLY && (k > 1 || k < nargs - 1)) continue;2392countTest();2393calledLog.clear();2394inv = MethodHandles.spreadInvoker(type, k);2395MethodType expType = (type.dropParameterTypes(k, nargs)2396.appendParameterTypes(Object[].class)2397.insertParameterTypes(0, MethodHandle.class));2398assertEquals(expType, inv.type());2399List<Object> targetPlusVarArgs = new ArrayList<>(targetPlusArgs);2400List<Object> tailList = targetPlusVarArgs.subList(1+k, 1+nargs);2401Object[] tail = tailList.toArray();2402tailList.clear(); tailList.add(tail);2403result = inv.invokeWithArguments(targetPlusVarArgs);2404if (testRetCode) assertEquals(code, result);2405assertCalled("invokee", args);2406}24072408// dynamic invoker2409countTest();2410CallSite site = new MutableCallSite(type);2411inv = site.dynamicInvoker();24122413// see if we get the result of the original target:2414try {2415result = inv.invokeWithArguments(args);2416assertTrue("should not reach here", false);2417} catch (IllegalStateException ex) {2418String msg = ex.getMessage();2419assertTrue(msg, msg.contains("site"));2420}24212422// set new target after invoker is created, to make sure we track target2423site.setTarget(target);2424calledLog.clear();2425result = inv.invokeWithArguments(args);2426if (testRetCode) assertEquals(code, result);2427assertCalled("invokee", args);2428}24292430static Object invokee(Object... args) {2431return called("invokee", args).hashCode();2432}24332434private static final String MISSING_ARG = "missingArg";2435private static final String MISSING_ARG_2 = "missingArg#2";2436static Object targetIfEquals() {2437return called("targetIfEquals");2438}2439static Object fallbackIfNotEquals() {2440return called("fallbackIfNotEquals");2441}2442static Object targetIfEquals(Object x) {2443assertEquals(x, MISSING_ARG);2444return called("targetIfEquals", x);2445}2446static Object fallbackIfNotEquals(Object x) {2447assertFalse(x.toString(), x.equals(MISSING_ARG));2448return called("fallbackIfNotEquals", x);2449}2450static Object targetIfEquals(Object x, Object y) {2451assertEquals(x, y);2452return called("targetIfEquals", x, y);2453}2454static Object fallbackIfNotEquals(Object x, Object y) {2455assertFalse(x.toString(), x.equals(y));2456return called("fallbackIfNotEquals", x, y);2457}2458static Object targetIfEquals(Object x, Object y, Object z) {2459assertEquals(x, y);2460return called("targetIfEquals", x, y, z);2461}2462static Object fallbackIfNotEquals(Object x, Object y, Object z) {2463assertFalse(x.toString(), x.equals(y));2464return called("fallbackIfNotEquals", x, y, z);2465}24662467@Test2468public void testGuardWithTest() throws Throwable {2469CodeCacheOverflowProcessor.runMHTest(this::testGuardWithTest0);2470}24712472public void testGuardWithTest0() throws Throwable {2473if (CAN_SKIP_WORKING) return;2474startTest("guardWithTest");2475for (int nargs = 0; nargs <= 50; nargs++) {2476if (CAN_TEST_LIGHTLY && nargs > 7) break;2477testGuardWithTest(nargs, Object.class);2478testGuardWithTest(nargs, String.class);2479}2480}2481void testGuardWithTest(int nargs, Class<?> argClass) throws Throwable {2482testGuardWithTest(nargs, 0, argClass);2483if (nargs <= 5 || nargs % 10 == 3) {2484for (int testDrops = 1; testDrops <= nargs; testDrops++)2485testGuardWithTest(nargs, testDrops, argClass);2486}2487}2488void testGuardWithTest(int nargs, int testDrops, Class<?> argClass) throws Throwable {2489countTest();2490int nargs1 = Math.min(3, nargs);2491MethodHandle test = PRIVATE.findVirtual(Object.class, "equals", MethodType.methodType(boolean.class, Object.class));2492MethodHandle target = PRIVATE.findStatic(MethodHandlesTest.class, "targetIfEquals", MethodType.genericMethodType(nargs1));2493MethodHandle fallback = PRIVATE.findStatic(MethodHandlesTest.class, "fallbackIfNotEquals", MethodType.genericMethodType(nargs1));2494while (test.type().parameterCount() > nargs)2495// 0: test = constant(MISSING_ARG.equals(MISSING_ARG))2496// 1: test = lambda (_) MISSING_ARG.equals(_)2497test = MethodHandles.insertArguments(test, 0, MISSING_ARG);2498if (argClass != Object.class) {2499test = changeArgTypes(test, argClass);2500target = changeArgTypes(target, argClass);2501fallback = changeArgTypes(fallback, argClass);2502}2503int testArgs = nargs - testDrops;2504assert(testArgs >= 0);2505test = addTrailingArgs(test, Math.min(testArgs, nargs), argClass);2506target = addTrailingArgs(target, nargs, argClass);2507fallback = addTrailingArgs(fallback, nargs, argClass);2508Object[][] argLists = {2509{ },2510{ "foo" }, { MISSING_ARG },2511{ "foo", "foo" }, { "foo", "bar" },2512{ "foo", "foo", "baz" }, { "foo", "bar", "baz" }2513};2514for (Object[] argList : argLists) {2515Object[] argList1 = argList;2516if (argList.length != nargs) {2517if (argList.length != nargs1) continue;2518argList1 = Arrays.copyOf(argList, nargs);2519Arrays.fill(argList1, nargs1, nargs, MISSING_ARG_2);2520}2521MethodHandle test1 = test;2522if (test1.type().parameterCount() > testArgs) {2523int pc = test1.type().parameterCount();2524test1 = MethodHandles.insertArguments(test, testArgs, Arrays.copyOfRange(argList1, testArgs, pc));2525}2526MethodHandle mh = MethodHandles.guardWithTest(test1, target, fallback);2527assertEquals(target.type(), mh.type());2528boolean equals;2529switch (nargs) {2530case 0: equals = true; break;2531case 1: equals = MISSING_ARG.equals(argList[0]); break;2532default: equals = argList[0].equals(argList[1]); break;2533}2534String willCall = (equals ? "targetIfEquals" : "fallbackIfNotEquals");2535if (verbosity >= 3)2536System.out.println(logEntry(willCall, argList));2537Object result = mh.invokeWithArguments(argList1);2538assertCalled(willCall, argList);2539}2540}25412542@Test2543public void testThrowException() throws Throwable {2544CodeCacheOverflowProcessor.runMHTest(this::testThrowException0);2545}25462547public void testThrowException0() throws Throwable {2548if (CAN_SKIP_WORKING) return;2549startTest("throwException");2550testThrowException(int.class, new ClassCastException("testing"));2551testThrowException(void.class, new java.io.IOException("testing"));2552testThrowException(String.class, new LinkageError("testing"));2553}25542555void testThrowException(Class<?> returnType, Throwable thrown) throws Throwable {2556countTest();2557Class<? extends Throwable> exType = thrown.getClass();2558MethodHandle target = MethodHandles.throwException(returnType, exType);2559//System.out.println("throwing with "+target+" : "+thrown);2560MethodType expectedType = MethodType.methodType(returnType, exType);2561assertEquals(expectedType, target.type());2562target = target.asType(target.type().generic());2563Throwable caught = null;2564try {2565Object res = target.invokeExact((Object) thrown);2566fail("got "+res+" instead of throwing "+thrown);2567} catch (Throwable ex) {2568if (ex != thrown) {2569if (ex instanceof Error) throw (Error)ex;2570if (ex instanceof RuntimeException) throw (RuntimeException)ex;2571}2572caught = ex;2573}2574assertSame(thrown, caught);2575}25762577@Test2578public void testInterfaceCast() throws Throwable {2579CodeCacheOverflowProcessor.runMHTest(this::testInterfaceCast0);2580}25812582public void testInterfaceCast0() throws Throwable {2583//if (CAN_SKIP_WORKING) return;2584startTest("interfaceCast");2585assert( (((Object)"foo") instanceof CharSequence));2586assert(!(((Object)"foo") instanceof Iterable));2587for (MethodHandle mh : new MethodHandle[]{2588MethodHandles.identity(String.class),2589MethodHandles.identity(CharSequence.class),2590MethodHandles.identity(Iterable.class)2591}) {2592if (verbosity > 0) System.out.println("-- mh = "+mh);2593for (Class<?> ctype : new Class<?>[]{2594Object.class, String.class, CharSequence.class,2595Number.class, Iterable.class2596}) {2597if (verbosity > 0) System.out.println("---- ctype = "+ctype.getName());2598// doret docast2599testInterfaceCast(mh, ctype, false, false);2600testInterfaceCast(mh, ctype, true, false);2601testInterfaceCast(mh, ctype, false, true);2602testInterfaceCast(mh, ctype, true, true);2603}2604}2605}2606private static Class<?> i2o(Class<?> c) {2607return (c.isInterface() ? Object.class : c);2608}2609public void testInterfaceCast(MethodHandle mh, Class<?> ctype,2610boolean doret, boolean docast) throws Throwable {2611MethodHandle mh0 = mh;2612if (verbosity > 1)2613System.out.println("mh="+mh+", ctype="+ctype.getName()+", doret="+doret+", docast="+docast);2614String normalRetVal = "normal return value";2615MethodType mt = mh.type();2616MethodType mt0 = mt;2617if (doret) mt = mt.changeReturnType(ctype);2618else mt = mt.changeParameterType(0, ctype);2619if (docast) mh = MethodHandles.explicitCastArguments(mh, mt);2620else mh = mh.asType(mt);2621assertEquals(mt, mh.type());2622MethodType mt1 = mt;2623// this bit is needed to make the interface types disappear for invokeWithArguments:2624mh = MethodHandles.explicitCastArguments(mh, mt.generic());2625Class<?>[] step = {2626mt1.parameterType(0), // param as passed to mh at first2627mt0.parameterType(0), // param after incoming cast2628mt0.returnType(), // return value before cast2629mt1.returnType(), // return value after outgoing cast2630};2631// where might a checkCast occur?2632boolean[] checkCast = new boolean[step.length];2633// the string value must pass each step without causing an exception2634if (!docast) {2635if (!doret) {2636if (step[0] != step[1])2637checkCast[1] = true; // incoming value is cast2638} else {2639if (step[2] != step[3])2640checkCast[3] = true; // outgoing value is cast2641}2642}2643boolean expectFail = false;2644for (int i = 0; i < step.length; i++) {2645Class<?> c = step[i];2646if (!checkCast[i]) c = i2o(c);2647if (!c.isInstance(normalRetVal)) {2648if (verbosity > 3)2649System.out.println("expect failure at step "+i+" in "+Arrays.toString(step)+Arrays.toString(checkCast));2650expectFail = true;2651break;2652}2653}2654countTest(!expectFail);2655if (verbosity > 2)2656System.out.println("expectFail="+expectFail+", mt="+mt);2657Object res;2658try {2659res = mh.invokeWithArguments(normalRetVal);2660} catch (Exception ex) {2661res = ex;2662}2663boolean sawFail = !(res instanceof String);2664if (sawFail != expectFail) {2665System.out.println("*** testInterfaceCast: mh0 = "+mh0);2666System.out.println(" retype using "+(docast ? "explicitCastArguments" : "asType")+" to "+mt+" => "+mh);2667System.out.println(" call returned "+res);2668System.out.println(" expected "+(expectFail ? "an exception" : normalRetVal));2669}2670if (!expectFail) {2671assertFalse(res.toString(), sawFail);2672assertEquals(normalRetVal, res);2673} else {2674assertTrue(res.toString(), sawFail);2675}2676}26772678@Test // SLOW2679public void testCastFailure() throws Throwable {2680CodeCacheOverflowProcessor.runMHTest(this::testCastFailure0);2681}26822683public void testCastFailure0() throws Throwable {2684if (CAN_SKIP_WORKING) return;2685startTest("testCastFailure");2686testCastFailure("cast/argument", 11000);2687if (CAN_TEST_LIGHTLY) return;2688testCastFailure("unbox/argument", 11000);2689testCastFailure("cast/return", 11000);2690testCastFailure("unbox/return", 11000);2691}26922693static class Surprise {2694public MethodHandle asMethodHandle() {2695return VALUE.bindTo(this);2696}2697Object value(Object x) {2698trace("value", x);2699if (boo != null) return boo;2700return x;2701}2702Object boo;2703void boo(Object x) { boo = x; }27042705static void trace(String x, Object y) {2706if (verbosity > 8) System.out.println(x+"="+y);2707}2708static Object refIdentity(Object x) { trace("ref.x", x); return x; }2709static Integer boxIdentity(Integer x) { trace("box.x", x); return x; }2710static int intIdentity(int x) { trace("int.x", x); return x; }2711static MethodHandle VALUE, REF_IDENTITY, BOX_IDENTITY, INT_IDENTITY;2712static {2713try {2714VALUE = PRIVATE.findVirtual(2715Surprise.class, "value",2716MethodType.methodType(Object.class, Object.class));2717REF_IDENTITY = PRIVATE.findStatic(2718Surprise.class, "refIdentity",2719MethodType.methodType(Object.class, Object.class));2720BOX_IDENTITY = PRIVATE.findStatic(2721Surprise.class, "boxIdentity",2722MethodType.methodType(Integer.class, Integer.class));2723INT_IDENTITY = PRIVATE.findStatic(2724Surprise.class, "intIdentity",2725MethodType.methodType(int.class, int.class));2726} catch (NoSuchMethodException | IllegalAccessException ex) {2727throw new RuntimeException(ex);2728}2729}2730}27312732@SuppressWarnings("ConvertToStringSwitch")2733void testCastFailure(String mode, int okCount) throws Throwable {2734countTest(false);2735if (verbosity > 2) System.out.println("mode="+mode);2736Surprise boo = new Surprise();2737MethodHandle identity = Surprise.REF_IDENTITY, surprise0 = boo.asMethodHandle(), surprise = surprise0;2738if (mode.endsWith("/return")) {2739if (mode.equals("unbox/return")) {2740// fail on return to ((Integer)surprise).intValue2741surprise = surprise.asType(MethodType.methodType(int.class, Object.class));2742identity = identity.asType(MethodType.methodType(int.class, Object.class));2743} else if (mode.equals("cast/return")) {2744// fail on return to (Integer)surprise2745surprise = surprise.asType(MethodType.methodType(Integer.class, Object.class));2746identity = identity.asType(MethodType.methodType(Integer.class, Object.class));2747}2748} else if (mode.endsWith("/argument")) {2749MethodHandle callee = null;2750if (mode.equals("unbox/argument")) {2751// fail on handing surprise to int argument2752callee = Surprise.INT_IDENTITY;2753} else if (mode.equals("cast/argument")) {2754// fail on handing surprise to Integer argument2755callee = Surprise.BOX_IDENTITY;2756}2757if (callee != null) {2758callee = callee.asType(MethodType.genericMethodType(1));2759surprise = MethodHandles.filterArguments(callee, 0, surprise);2760identity = MethodHandles.filterArguments(callee, 0, identity);2761}2762}2763assertNotSame(mode, surprise, surprise0);2764identity = identity.asType(MethodType.genericMethodType(1));2765surprise = surprise.asType(MethodType.genericMethodType(1));2766Object x = 42;2767for (int i = 0; i < okCount; i++) {2768Object y = identity.invokeExact(x);2769assertEquals(x, y);2770Object z = surprise.invokeExact(x);2771assertEquals(x, z);2772}2773boo.boo("Boo!");2774Object y = identity.invokeExact(x);2775assertEquals(x, y);2776try {2777Object z = surprise.invokeExact(x);2778System.out.println("Failed to throw; got z="+z);2779assertTrue(false);2780} catch (ClassCastException ex) {2781if (verbosity > 2)2782System.out.println("caught "+ex);2783if (verbosity > 3)2784ex.printStackTrace(System.out);2785assertTrue(true); // all is well2786}2787}27882789static Example userMethod(Object o, String s, int i) {2790called("userMethod", o, s, i);2791return null;2792}27932794@Test2795public void testUserClassInSignature() throws Throwable {2796CodeCacheOverflowProcessor.runMHTest(this::testUserClassInSignature0);2797}27982799public void testUserClassInSignature0() throws Throwable {2800if (CAN_SKIP_WORKING) return;2801startTest("testUserClassInSignature");2802Lookup lookup = MethodHandles.lookup();2803String name; MethodType mt; MethodHandle mh;2804Object[] args;28052806// Try a static method.2807name = "userMethod";2808mt = MethodType.methodType(Example.class, Object.class, String.class, int.class);2809mh = lookup.findStatic(lookup.lookupClass(), name, mt);2810assertEquals(mt, mh.type());2811assertEquals(Example.class, mh.type().returnType());2812args = randomArgs(mh.type().parameterArray());2813mh.invokeWithArguments(args);2814assertCalled(name, args);28152816// Try a virtual method.2817name = "v2";2818mt = MethodType.methodType(Object.class, Object.class, int.class);2819mh = lookup.findVirtual(Example.class, name, mt);2820assertEquals(mt, mh.type().dropParameterTypes(0,1));2821assertTrue(mh.type().parameterList().contains(Example.class));2822args = randomArgs(mh.type().parameterArray());2823mh.invokeWithArguments(args);2824assertCalled(name, args);2825}28262827static void runForRunnable() {2828called("runForRunnable");2829}2830public interface Fooable {2831// overloads:2832Object foo(Object x, String y);2833List<?> foo(String x, int y);2834Object foo(String x);2835}2836static Object fooForFooable(String x, Object... y) {2837return called("fooForFooable/"+x, y);2838}2839@SuppressWarnings("serial") // not really a public API, just a test case2840public static class MyCheckedException extends Exception {2841}2842public interface WillThrow {2843void willThrow() throws MyCheckedException;2844}2845/*non-public*/ interface PrivateRunnable {2846public void run();2847}28482849@Test2850public void testAsInterfaceInstance() throws Throwable {2851CodeCacheOverflowProcessor.runMHTest(this::testAsInterfaceInstance0);2852}28532854public void testAsInterfaceInstance0() throws Throwable {2855if (CAN_SKIP_WORKING) return;2856startTest("asInterfaceInstance");2857Lookup lookup = MethodHandles.lookup();2858// test typical case: Runnable.run2859{2860countTest();2861if (verbosity >= 2) System.out.println("Runnable");2862MethodType mt = MethodType.methodType(void.class);2863MethodHandle mh = lookup.findStatic(MethodHandlesTest.class, "runForRunnable", mt);2864Runnable proxy = MethodHandleProxies.asInterfaceInstance(Runnable.class, mh);2865proxy.run();2866assertCalled("runForRunnable");2867}2868// well known single-name overloaded interface: Appendable.append2869{2870countTest();2871if (verbosity >= 2) System.out.println("Appendable");2872ArrayList<List<?>> appendResults = new ArrayList<>();2873MethodHandle append = lookup.bind(appendResults, "add", MethodType.methodType(boolean.class, Object.class));2874append = append.asType(MethodType.methodType(void.class, List.class)); // specialize the type2875MethodHandle asList = lookup.findStatic(Arrays.class, "asList", MethodType.methodType(List.class, Object[].class));2876MethodHandle mh = MethodHandles.filterReturnValue(asList, append).asVarargsCollector(Object[].class);2877Appendable proxy = MethodHandleProxies.asInterfaceInstance(Appendable.class, mh);2878proxy.append("one");2879proxy.append("two", 3, 4);2880proxy.append('5');2881assertEquals(Arrays.asList(Arrays.asList("one"),2882Arrays.asList("two", 3, 4),2883Arrays.asList('5')),2884appendResults);2885if (verbosity >= 3) System.out.println("appendResults="+appendResults);2886appendResults.clear();2887Formatter formatter = new Formatter(proxy);2888String fmt = "foo str=%s char='%c' num=%d";2889Object[] fmtArgs = { "str!", 'C', 42 };2890String expect = String.format(fmt, fmtArgs);2891formatter.format(fmt, fmtArgs);2892String actual = "";2893if (verbosity >= 3) System.out.println("appendResults="+appendResults);2894for (List<?> l : appendResults) {2895Object x = l.get(0);2896switch (l.size()) {2897case 1: actual += x; continue;2898case 3: actual += ((String)x).substring((int)(Object)l.get(1), (int)(Object)l.get(2)); continue;2899}2900actual += l;2901}2902if (verbosity >= 3) System.out.println("expect="+expect);2903if (verbosity >= 3) System.out.println("actual="+actual);2904assertEquals(expect, actual);2905}2906// test case of an single name which is overloaded: Fooable.foo(...)2907{2908if (verbosity >= 2) System.out.println("Fooable");2909MethodHandle mh = lookup.findStatic(MethodHandlesTest.class, "fooForFooable",2910MethodType.methodType(Object.class, String.class, Object[].class));2911Fooable proxy = MethodHandleProxies.asInterfaceInstance(Fooable.class, mh);2912for (Method m : Fooable.class.getDeclaredMethods()) {2913countTest();2914assertSame("foo", m.getName());2915if (verbosity > 3)2916System.out.println("calling "+m);2917MethodHandle invoker = lookup.unreflect(m);2918MethodType mt = invoker.type();2919Class<?>[] types = mt.parameterArray();2920types[0] = int.class; // placeholder2921Object[] args = randomArgs(types);2922args[0] = proxy;2923if (verbosity > 3)2924System.out.println("calling "+m+" on "+Arrays.asList(args));2925Object result = invoker.invokeWithArguments(args);2926if (verbosity > 4)2927System.out.println("result = "+result);2928String name = "fooForFooable/"+args[1];2929Object[] argTail = Arrays.copyOfRange(args, 2, args.length);2930assertCalled(name, argTail);2931assertEquals(result, logEntry(name, argTail));2932}2933}2934// test processing of thrown exceptions:2935for (Throwable ex : new Throwable[] { new NullPointerException("ok"),2936new InternalError("ok"),2937new Throwable("fail"),2938new Exception("fail"),2939new MyCheckedException()2940}) {2941MethodHandle mh = MethodHandles.throwException(void.class, Throwable.class);2942mh = MethodHandles.insertArguments(mh, 0, ex);2943WillThrow proxy = MethodHandleProxies.asInterfaceInstance(WillThrow.class, mh);2944try {2945countTest();2946proxy.willThrow();2947System.out.println("Failed to throw: "+ex);2948assertTrue(false);2949} catch (Throwable ex1) {2950if (verbosity > 3) {2951System.out.println("throw "+ex);2952System.out.println("catch "+(ex == ex1 ? "UNWRAPPED" : ex1));2953}2954if (ex instanceof RuntimeException ||2955ex instanceof Error) {2956assertSame("must pass unchecked exception out without wrapping", ex, ex1);2957} else if (ex instanceof MyCheckedException) {2958assertSame("must pass declared exception out without wrapping", ex, ex1);2959} else {2960assertNotSame("must pass undeclared checked exception with wrapping", ex, ex1);2961if (!(ex1 instanceof UndeclaredThrowableException) || ex1.getCause() != ex) {2962ex1.printStackTrace(System.out);2963}2964assertSame(ex, ex1.getCause());2965UndeclaredThrowableException utex = (UndeclaredThrowableException) ex1;2966}2967}2968}2969// Test error checking on bad interfaces:2970for (Class<?> nonSMI : new Class<?>[] { Object.class,2971String.class,2972CharSequence.class,2973java.io.Serializable.class,2974PrivateRunnable.class,2975Example.class }) {2976if (verbosity > 2) System.out.println(nonSMI.getName());2977try {2978countTest(false);2979MethodHandleProxies.asInterfaceInstance(nonSMI, varargsArray(0));2980assertTrue("Failed to throw on "+nonSMI.getName(), false);2981} catch (IllegalArgumentException ex) {2982if (verbosity > 2) System.out.println(nonSMI.getSimpleName()+": "+ex);2983// Object: java.lang.IllegalArgumentException:2984// not a public interface: java.lang.Object2985// String: java.lang.IllegalArgumentException:2986// not a public interface: java.lang.String2987// CharSequence: java.lang.IllegalArgumentException:2988// not a single-method interface: java.lang.CharSequence2989// Serializable: java.lang.IllegalArgumentException:2990// not a single-method interface: java.io.Serializable2991// PrivateRunnable: java.lang.IllegalArgumentException:2992// not a public interface: test.java.lang.invoke.MethodHandlesTest$PrivateRunnable2993// Example: java.lang.IllegalArgumentException:2994// not a public interface: test.java.lang.invoke.MethodHandlesTest$Example2995}2996}2997// Test error checking on interfaces with the wrong method type:2998for (Class<?> intfc : new Class<?>[] { Runnable.class /*arity 0*/,2999Fooable.class /*arity 1 & 2*/ }) {3000int badArity = 1; // known to be incompatible3001if (verbosity > 2) System.out.println(intfc.getName());3002try {3003countTest(false);3004MethodHandleProxies.asInterfaceInstance(intfc, varargsArray(badArity));3005assertTrue("Failed to throw on "+intfc.getName(), false);3006} catch (WrongMethodTypeException ex) {3007if (verbosity > 2) System.out.println(intfc.getSimpleName()+": "+ex);3008// Runnable: java.lang.invoke.WrongMethodTypeException:3009// cannot convert MethodHandle(Object)Object[] to ()void3010// Fooable: java.lang.invoke.WrongMethodTypeException:3011// cannot convert MethodHandle(Object)Object[] to (Object,String)Object3012}3013}3014}30153016@Test3017public void testRunnableProxy() throws Throwable {3018CodeCacheOverflowProcessor.runMHTest(this::testRunnableProxy0);3019}30203021public void testRunnableProxy0() throws Throwable {3022if (CAN_SKIP_WORKING) return;3023startTest("testRunnableProxy");3024MethodHandles.Lookup lookup = MethodHandles.lookup();3025MethodHandle run = lookup.findStatic(lookup.lookupClass(), "runForRunnable", MethodType.methodType(void.class));3026Runnable r = MethodHandleProxies.asInterfaceInstance(Runnable.class, run);3027testRunnableProxy(r);3028assertCalled("runForRunnable");3029}3030private static void testRunnableProxy(Runnable r) {3031//7058630: JSR 292 method handle proxy violates contract for Object methods3032r.run();3033Object o = r;3034r = null;3035boolean eq = (o == o);3036int hc = System.identityHashCode(o);3037String st = o.getClass().getName() + "@" + Integer.toHexString(hc);3038Object expect = Arrays.asList(st, eq, hc);3039if (verbosity >= 2) System.out.println("expect st/eq/hc = "+expect);3040Object actual = Arrays.asList(o.toString(), o.equals(o), o.hashCode());3041if (verbosity >= 2) System.out.println("actual st/eq/hc = "+actual);3042assertEquals(expect, actual);3043}3044}3045// Local abbreviated copy of sun.invoke.util.ValueConversions3046// This guy tests access from outside the same package member, but inside3047// the package itself.3048class ValueConversions {3049private static final Lookup IMPL_LOOKUP = MethodHandles.lookup();3050private static final Object[] NO_ARGS_ARRAY = {};3051private static Object[] makeArray(Object... args) { return args; }3052private static Object[] array() { return NO_ARGS_ARRAY; }3053private static Object[] array(Object a0)3054{ return makeArray(a0); }3055private static Object[] array(Object a0, Object a1)3056{ return makeArray(a0, a1); }3057private static Object[] array(Object a0, Object a1, Object a2)3058{ return makeArray(a0, a1, a2); }3059private static Object[] array(Object a0, Object a1, Object a2, Object a3)3060{ return makeArray(a0, a1, a2, a3); }3061private static Object[] array(Object a0, Object a1, Object a2, Object a3,3062Object a4)3063{ return makeArray(a0, a1, a2, a3, a4); }3064private static Object[] array(Object a0, Object a1, Object a2, Object a3,3065Object a4, Object a5)3066{ return makeArray(a0, a1, a2, a3, a4, a5); }3067private static Object[] array(Object a0, Object a1, Object a2, Object a3,3068Object a4, Object a5, Object a6)3069{ return makeArray(a0, a1, a2, a3, a4, a5, a6); }3070private static Object[] array(Object a0, Object a1, Object a2, Object a3,3071Object a4, Object a5, Object a6, Object a7)3072{ return makeArray(a0, a1, a2, a3, a4, a5, a6, a7); }3073private static Object[] array(Object a0, Object a1, Object a2, Object a3,3074Object a4, Object a5, Object a6, Object a7,3075Object a8)3076{ return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8); }3077private static Object[] array(Object a0, Object a1, Object a2, Object a3,3078Object a4, Object a5, Object a6, Object a7,3079Object a8, Object a9)3080{ return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }3081static MethodHandle[] makeArrays() {3082ArrayList<MethodHandle> arrays = new ArrayList<>();3083MethodHandles.Lookup lookup = IMPL_LOOKUP;3084for (;;) {3085int nargs = arrays.size();3086MethodType type = MethodType.genericMethodType(nargs).changeReturnType(Object[].class);3087String name = "array";3088MethodHandle array = null;3089try {3090array = lookup.findStatic(ValueConversions.class, name, type);3091} catch (ReflectiveOperationException ex) {3092// break from loop!3093}3094if (array == null) break;3095arrays.add(array);3096}3097assertTrue(arrays.size() == 11); // current number of methods3098return arrays.toArray(new MethodHandle[0]);3099}3100static final MethodHandle[] ARRAYS = makeArrays();31013102/** Return a method handle that takes the indicated number of Object3103* arguments and returns an Object array of them, as if for varargs.3104*/3105public static MethodHandle varargsArray(int nargs) {3106if (nargs < ARRAYS.length)3107return ARRAYS[nargs];3108return MethodHandles.identity(Object[].class).asCollector(Object[].class, nargs);3109}3110public static MethodHandle varargsArray(Class<?> arrayType, int nargs) {3111Class<?> elemType = arrayType.getComponentType();3112MethodType vaType = MethodType.methodType(arrayType, Collections.<Class<?>>nCopies(nargs, elemType));3113MethodHandle mh = varargsArray(nargs);3114if (arrayType != Object[].class)3115mh = MethodHandles.filterReturnValue(mh, CHANGE_ARRAY_TYPE.bindTo(arrayType));3116return mh.asType(vaType);3117}3118static Object changeArrayType(Class<?> arrayType, Object[] a) {3119Class<?> elemType = arrayType.getComponentType();3120if (!elemType.isPrimitive())3121return Arrays.copyOf(a, a.length, arrayType.asSubclass(Object[].class));3122Object b = java.lang.reflect.Array.newInstance(elemType, a.length);3123for (int i = 0; i < a.length; i++)3124java.lang.reflect.Array.set(b, i, a[i]);3125return b;3126}3127private static final MethodHandle CHANGE_ARRAY_TYPE;3128static {3129try {3130CHANGE_ARRAY_TYPE = IMPL_LOOKUP.findStatic(ValueConversions.class, "changeArrayType",3131MethodType.methodType(Object.class, Class.class, Object[].class));3132} catch (NoSuchMethodException | IllegalAccessException ex) {3133Error err = new InternalError("uncaught exception");3134err.initCause(ex);3135throw err;3136}3137}31383139private static final List<Object> NO_ARGS_LIST = Arrays.asList(NO_ARGS_ARRAY);3140private static List<Object> makeList(Object... args) { return Arrays.asList(args); }3141private static List<Object> list() { return NO_ARGS_LIST; }3142private static List<Object> list(Object a0)3143{ return makeList(a0); }3144private static List<Object> list(Object a0, Object a1)3145{ return makeList(a0, a1); }3146private static List<Object> list(Object a0, Object a1, Object a2)3147{ return makeList(a0, a1, a2); }3148private static List<Object> list(Object a0, Object a1, Object a2, Object a3)3149{ return makeList(a0, a1, a2, a3); }3150private static List<Object> list(Object a0, Object a1, Object a2, Object a3,3151Object a4)3152{ return makeList(a0, a1, a2, a3, a4); }3153private static List<Object> list(Object a0, Object a1, Object a2, Object a3,3154Object a4, Object a5)3155{ return makeList(a0, a1, a2, a3, a4, a5); }3156private static List<Object> list(Object a0, Object a1, Object a2, Object a3,3157Object a4, Object a5, Object a6)3158{ return makeList(a0, a1, a2, a3, a4, a5, a6); }3159private static List<Object> list(Object a0, Object a1, Object a2, Object a3,3160Object a4, Object a5, Object a6, Object a7)3161{ return makeList(a0, a1, a2, a3, a4, a5, a6, a7); }3162private static List<Object> list(Object a0, Object a1, Object a2, Object a3,3163Object a4, Object a5, Object a6, Object a7,3164Object a8)3165{ return makeList(a0, a1, a2, a3, a4, a5, a6, a7, a8); }3166private static List<Object> list(Object a0, Object a1, Object a2, Object a3,3167Object a4, Object a5, Object a6, Object a7,3168Object a8, Object a9)3169{ return makeList(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }3170static MethodHandle[] makeLists() {3171ArrayList<MethodHandle> lists = new ArrayList<>();3172MethodHandles.Lookup lookup = IMPL_LOOKUP;3173for (;;) {3174int nargs = lists.size();3175MethodType type = MethodType.genericMethodType(nargs).changeReturnType(List.class);3176String name = "list";3177MethodHandle list = null;3178try {3179list = lookup.findStatic(ValueConversions.class, name, type);3180} catch (ReflectiveOperationException ex) {3181// break from loop!3182}3183if (list == null) break;3184lists.add(list);3185}3186assertTrue(lists.size() == 11); // current number of methods3187return lists.toArray(new MethodHandle[0]);3188}3189static final MethodHandle[] LISTS = makeLists();3190static final MethodHandle AS_LIST;3191static {3192try {3193AS_LIST = IMPL_LOOKUP.findStatic(Arrays.class, "asList", MethodType.methodType(List.class, Object[].class));3194} catch (NoSuchMethodException | IllegalAccessException ex) { throw new RuntimeException(ex); }3195}31963197/** Return a method handle that takes the indicated number of Object3198* arguments and returns List.3199*/3200public static MethodHandle varargsList(int nargs) {3201if (nargs < LISTS.length)3202return LISTS[nargs];3203return AS_LIST.asCollector(Object[].class, nargs);3204}3205}3206// This guy tests access from outside the same package member, but inside3207// the package itself.3208class PackageSibling {3209static Lookup lookup() {3210return MethodHandles.lookup();3211}3212}321332143215