7032323: code changes for JSR 292 EG adjustments to API, through Public Review
Summary: API code changes and javadoc changes following JSR 292 Public Review comments, through PFD
Reviewed-by: never
diff --git a/test/java/lang/invoke/6998541/Test6998541.java b/test/java/lang/invoke/6998541/Test6998541.java
index 0f64eee..e9f467b 100644
--- a/test/java/lang/invoke/6998541/Test6998541.java
+++ b/test/java/lang/invoke/6998541/Test6998541.java
@@ -164,6 +164,7 @@
private static boolean canDoAsType(Class<?> src, Class<?> dst) {
if (src == dst) return true;
if (dst == void.class) return true;
+ if (src == void.class) return true; // allow void->zero
if (!src.isPrimitive() || !dst.isPrimitive()) return true;
// primitive conversion works for asType only when it's widening
if (src == boolean.class || dst == boolean.class) return false;
@@ -451,7 +452,6 @@
private final static MethodHandle mh_dv = mh(double.class );
private static void void2prim(int i) throws Throwable {
- if (!DO_CASTS) return;
assertEquals( false, (boolean) mh_zv.invokeExact()); // void -> boolean
assertEquals((byte) 0, (byte) mh_bv.invokeExact()); // void -> byte
assertEquals((char) 0, (char) mh_cv.invokeExact()); // void -> char
@@ -463,15 +463,7 @@
}
private static void void2prim_invalid(double x) throws Throwable {
- if (DO_CASTS) return;
- try { assertEquals( false, (boolean) mh_zv.invokeExact()); fail(); } catch (NullPointerException _) {} // void -> boolean
- try { assertEquals((byte) 0, (byte) mh_bv.invokeExact()); fail(); } catch (NullPointerException _) {} // void -> byte
- try { assertEquals((char) 0, (char) mh_cv.invokeExact()); fail(); } catch (NullPointerException _) {} // void -> char
- try { assertEquals((short) 0, (short) mh_sv.invokeExact()); fail(); } catch (NullPointerException _) {} // void -> short
- try { assertEquals( 0, (int) mh_iv.invokeExact()); fail(); } catch (NullPointerException _) {} // void -> int
- try { assertEquals( 0L, (long) mh_jv.invokeExact()); fail(); } catch (NullPointerException _) {} // void -> long
- try { assertEquals( 0.0f, (float) mh_fv.invokeExact()); fail(); } catch (NullPointerException _) {} // void -> float
- try { assertEquals( 0.0d, (double) mh_dv.invokeExact()); fail(); } catch (NullPointerException _) {} // void -> double
+ // no cases
}
private static MethodHandle mh_v(Class arg) { return mh(void.class, arg); }
diff --git a/test/java/lang/invoke/InvokeDynamicPrintArgs.java b/test/java/lang/invoke/InvokeDynamicPrintArgs.java
index d8a395d..9c3db42 100644
--- a/test/java/lang/invoke/InvokeDynamicPrintArgs.java
+++ b/test/java/lang/invoke/InvokeDynamicPrintArgs.java
@@ -106,8 +106,10 @@
"Done printing argument lists."
};
+ private static boolean doPrint = true;
private static void printArgs(Object bsmInfo, Object... args) {
- System.out.println(bsmInfo+Arrays.deepToString(args));
+ String message = bsmInfo+Arrays.deepToString(args);
+ if (doPrint) System.out.println(message);
}
private static MethodHandle MH_printArgs() throws ReflectiveOperationException {
shouldNotCallThis();
@@ -129,11 +131,48 @@
return lookup().findStatic(lookup().lookupClass(), "bsm", MT_bsm());
}
- private static CallSite bsm2(Lookup caller, String name, MethodType type, Object... arg) throws ReflectiveOperationException {
+ /* Example of a constant call site with user-data.
+ * In this case, the user data is exactly the BSM data.
+ * Note that a CCS with user data must use the "hooked" constructor
+ * to bind the CCS itself into the resulting target.
+ * A normal constructor would not allow a circular relation
+ * between the CCS and its target.
+ */
+ public static class PrintingCallSite extends ConstantCallSite {
+ final Lookup caller;
+ final String name;
+ final Object[] staticArgs;
+
+ PrintingCallSite(Lookup caller, String name, MethodType type, Object... staticArgs) throws Throwable {
+ super(type, MH_createTarget());
+ this.caller = caller;
+ this.name = name;
+ this.staticArgs = staticArgs;
+ }
+
+ public MethodHandle createTarget() {
+ try {
+ return lookup().bind(this, "runTarget", genericMethodType(0, true)).asType(type());
+ } catch (ReflectiveOperationException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ public Object runTarget(Object... dynamicArgs) {
+ List<Object> bsmInfo = new ArrayList<>(Arrays.asList(caller, name, type()));
+ bsmInfo.addAll(Arrays.asList(staticArgs));
+ printArgs(bsmInfo, dynamicArgs);
+ return null;
+ }
+
+ private static MethodHandle MH_createTarget() throws ReflectiveOperationException {
+ shouldNotCallThis();
+ return lookup().findVirtual(lookup().lookupClass(), "createTarget", methodType(MethodHandle.class));
+ }
+ }
+ private static CallSite bsm2(Lookup caller, String name, MethodType type, Object... arg) throws Throwable {
// ignore caller and name, but match the type:
- List<Object> bsmInfo = new ArrayList<>(Arrays.asList(caller, name, type));
- bsmInfo.addAll(Arrays.asList((Object[])arg));
- return new ConstantCallSite(MH_printArgs().bindTo(bsmInfo).asCollector(Object[].class, type.parameterCount()).asType(type));
+ return new PrintingCallSite(caller, name, type, arg);
}
private static MethodType MT_bsm2() {
shouldNotCallThis();
@@ -146,33 +185,33 @@
private static MethodHandle INDY_nothing() throws Throwable {
shouldNotCallThis();
- return ((CallSite) MH_bsm().invokeGeneric(lookup(),
+ return ((CallSite) MH_bsm().invoke(lookup(),
"nothing", methodType(void.class)
)).dynamicInvoker();
}
private static MethodHandle INDY_foo() throws Throwable {
shouldNotCallThis();
- return ((CallSite) MH_bsm().invokeGeneric(lookup(),
+ return ((CallSite) MH_bsm().invoke(lookup(),
"foo", methodType(void.class, String.class)
)).dynamicInvoker();
}
private static MethodHandle INDY_bar() throws Throwable {
shouldNotCallThis();
- return ((CallSite) MH_bsm2().invokeGeneric(lookup(),
+ return ((CallSite) MH_bsm2().invoke(lookup(),
"bar", methodType(void.class, String.class, int.class)
, Void.class, "void type!", 1, 234.5F, 67.5, (long)89
)).dynamicInvoker();
}
private static MethodHandle INDY_bar2() throws Throwable {
shouldNotCallThis();
- return ((CallSite) MH_bsm2().invokeGeneric(lookup(),
+ return ((CallSite) MH_bsm2().invoke(lookup(),
"bar2", methodType(void.class, String.class, int.class)
, Void.class, "void type!", 1, 234.5F, 67.5, (long)89
)).dynamicInvoker();
}
private static MethodHandle INDY_baz() throws Throwable {
shouldNotCallThis();
- return ((CallSite) MH_bsm2().invokeGeneric(lookup(),
+ return ((CallSite) MH_bsm2().invoke(lookup(),
"baz", methodType(void.class, String.class, int.class, double.class)
, 1234.5
)).dynamicInvoker();
diff --git a/test/java/lang/invoke/InvokeGenericTest.java b/test/java/lang/invoke/InvokeGenericTest.java
index 3d49333..fecd2f0 100644
--- a/test/java/lang/invoke/InvokeGenericTest.java
+++ b/test/java/lang/invoke/InvokeGenericTest.java
@@ -314,7 +314,7 @@
ArrayList<Class<?>> argTypes = new ArrayList<Class<?>>(targetType.parameterList());
Collections.fill(argTypes.subList(beg, end), argType);
MethodType ttype2 = MethodType.methodType(targetType.returnType(), argTypes);
- return MethodHandles.convertArguments(target, ttype2);
+ return target.asType(ttype2);
}
// This lookup is good for all members in and under InvokeGenericTest.
@@ -378,7 +378,7 @@
String[] args = { "one", "two" };
MethodHandle mh = callable(Object.class, String.class);
Object res; List resl;
- res = resl = (List) mh.invokeGeneric((String)args[0], (Object)args[1]);
+ res = resl = (List) mh.invoke((String)args[0], (Object)args[1]);
//System.out.println(res);
assertEquals(Arrays.asList(args), res);
}
diff --git a/test/java/lang/invoke/JavaDocExamplesTest.java b/test/java/lang/invoke/JavaDocExamplesTest.java
index 9f68a20..0e373c1 100644
--- a/test/java/lang/invoke/JavaDocExamplesTest.java
+++ b/test/java/lang/invoke/JavaDocExamplesTest.java
@@ -34,7 +34,7 @@
$ $JAVA7X_HOME/bin/javac -cp $JUNIT4_JAR -d /tmp/Classes \
$DAVINCI/sources/jdk/test/java/lang/invoke/JavaDocExamplesTest.java
$ $JAVA7X_HOME/bin/java -cp $JUNIT4_JAR:/tmp/Classes \
- -Dtest.java.lang.invoke.JavaDocExamplesTest.verbosity=1 \
+ -DJavaDocExamplesTest.verbosity=1 \
test.java.lang.invoke.JavaDocExamplesTest
----
*/
@@ -45,12 +45,10 @@
import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*;
-import java.lang.reflect.*;
import java.util.*;
import org.junit.*;
import static org.junit.Assert.*;
-import static org.junit.Assume.*;
/**
@@ -60,11 +58,29 @@
/** Wrapper for running the JUnit tests in this module.
* Put JUnit on the classpath!
*/
- public static void main(String... ignore) {
- org.junit.runner.JUnitCore.runClasses(JavaDocExamplesTest.class);
+ public static void main(String... ignore) throws Throwable {
+ System.out.println("can run this as:");
+ System.out.println("$ java org.junit.runner.JUnitCore "+JavaDocExamplesTest.class.getName());
+ new JavaDocExamplesTest().run();
+ }
+ public void run() throws Throwable {
+ testFindVirtual();
+ testPermuteArguments();
+ testDropArguments();
+ testFilterArguments();
+ testFoldArguments();
+ testMethodHandlesSummary();
+ testAsSpreader();
+ testAsCollector();
+ testAsVarargsCollector();
+ testAsFixedArity();
+ testAsTypeCornerCases();
+ testMutableCallSite();
}
// How much output?
- static int verbosity = Integer.getInteger("test.java.lang.invoke.JavaDocExamplesTest.verbosity", 0);
+ static final Class<?> THIS_CLASS = JavaDocExamplesTest.class;
+ static int verbosity = Integer.getInteger(THIS_CLASS.getSimpleName()+".verbosity", 0);
+
{}
static final private Lookup LOOKUP = lookup();
@@ -74,17 +90,23 @@
// "hashCode", methodType(int.class));
// form required if ReflectiveOperationException is intercepted:
-static final private MethodHandle CONCAT_2, HASHCODE_2;
+ static final private MethodHandle CONCAT_2, HASHCODE_2, ADD_2, SUB_2;
static {
try {
+ Class<?> THIS_CLASS = LOOKUP.lookupClass();
CONCAT_2 = LOOKUP.findVirtual(String.class,
"concat", methodType(String.class, String.class));
HASHCODE_2 = LOOKUP.findVirtual(Object.class,
"hashCode", methodType(int.class));
+ ADD_2 = LOOKUP.findStatic(THIS_CLASS, "add", methodType(int.class, int.class, int.class));
+ SUB_2 = LOOKUP.findStatic(THIS_CLASS, "sub", methodType(int.class, int.class, int.class));
} catch (ReflectiveOperationException ex) {
throw new RuntimeException(ex);
}
}
+ static int add(int x, int y) { return x + y; }
+ static int sub(int x, int y) { return x - y; }
+
{}
@Test public void testFindVirtual() throws Throwable {
@@ -101,6 +123,39 @@
assertEquals("xy".hashCode(), (int) HASHCODE_3.invokeExact((Object)"xy"));
{}
}
+
+ @Test public void testPermuteArguments() throws Throwable {
+ {{
+{} /// JAVADOC
+MethodType intfn1 = methodType(int.class, int.class);
+MethodType intfn2 = methodType(int.class, int.class, int.class);
+MethodHandle sub = SUB_2;// ... {int x, int y => x-y} ...;
+assert(sub.type().equals(intfn2));
+MethodHandle sub1 = permuteArguments(sub, intfn2, 0, 1);
+MethodHandle rsub = permuteArguments(sub, intfn2, 1, 0);
+assert((int)rsub.invokeExact(1, 100) == 99);
+MethodHandle add = ADD_2;// ... {int x, int y => x+y} ...;
+assert(add.type().equals(intfn2));
+MethodHandle twice = permuteArguments(add, intfn1, 0, 0);
+assert(twice.type().equals(intfn1));
+assert((int)twice.invokeExact(21) == 42);
+ }}
+ {{
+{} /// JAVADOC
+MethodHandle cat = lookup().findVirtual(String.class,
+ "concat", methodType(String.class, String.class));
+assertEquals("xy", (String) cat.invokeExact("x", "y"));
+MethodHandle d0 = dropArguments(cat, 0, String.class);
+assertEquals("yz", (String) d0.invokeExact("x", "y", "z"));
+MethodHandle d1 = dropArguments(cat, 1, String.class);
+assertEquals("xz", (String) d1.invokeExact("x", "y", "z"));
+MethodHandle d2 = dropArguments(cat, 2, String.class);
+assertEquals("xy", (String) d2.invokeExact("x", "y", "z"));
+MethodHandle d12 = dropArguments(cat, 1, int.class, boolean.class);
+assertEquals("xz", (String) d12.invokeExact("x", 12, true, "z"));
+ }}
+ }
+
@Test public void testDropArguments() throws Throwable {
{{
{} /// JAVADOC
@@ -145,6 +200,21 @@
}}
}
+ @Test public void testFoldArguments() throws Throwable {
+ {{
+{} /// JAVADOC
+MethodHandle trace = publicLookup().findVirtual(java.io.PrintStream.class,
+ "println", methodType(void.class, String.class))
+ .bindTo(System.out);
+MethodHandle cat = lookup().findVirtual(String.class,
+ "concat", methodType(String.class, String.class));
+assertEquals("boojum", (String) cat.invokeExact("boo", "jum"));
+MethodHandle catTrace = foldArguments(cat, trace);
+// also prints "boo":
+assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
+ }}
+ }
+
static void assertEquals(Object exp, Object act) {
if (verbosity > 0)
System.out.println("result: "+act);
@@ -162,24 +232,24 @@
mh = lookup.findVirtual(String.class, "replace", mt);
s = (String) mh.invokeExact("daddy",'d','n');
// invokeExact(Ljava/lang/String;CC)Ljava/lang/String;
-assert(s.equals("nanny"));
+assertEquals(s, "nanny");
// weakly typed invocation (using MHs.invoke)
s = (String) mh.invokeWithArguments("sappy", 'p', 'v');
-assert(s.equals("savvy"));
+assertEquals(s, "savvy");
// mt is (Object[])List
mt = MethodType.methodType(java.util.List.class, Object[].class);
mh = lookup.findStatic(java.util.Arrays.class, "asList", mt);
assert(mh.isVarargsCollector());
x = mh.invoke("one", "two");
// invoke(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;
-assert(x.equals(java.util.Arrays.asList("one","two")));
+assertEquals(x, java.util.Arrays.asList("one","two"));
// mt is (Object,Object,Object)Object
mt = MethodType.genericMethodType(3);
mh = mh.asType(mt);
x = mh.invokeExact((Object)1, (Object)2, (Object)3);
// invokeExact(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
-assert(x.equals(java.util.Arrays.asList(1,2,3)));
-// mt is { => int}
+assertEquals(x, java.util.Arrays.asList(1,2,3));
+// mt is ()int
mt = MethodType.methodType(int.class);
mh = lookup.findVirtual(java.util.List.class, "size", mt);
i = (int) mh.invokeExact(java.util.Arrays.asList(1,2,3));
@@ -193,37 +263,239 @@
}}
}
+ @Test public void testAsSpreader() throws Throwable {
+ {{
+{} /// JAVADOC
+MethodHandle equals = publicLookup()
+ .findVirtual(String.class, "equals", methodType(boolean.class, Object.class));
+assert( (boolean) equals.invokeExact("me", (Object)"me"));
+assert(!(boolean) equals.invokeExact("me", (Object)"thee"));
+// spread both arguments from a 2-array:
+MethodHandle eq2 = equals.asSpreader(Object[].class, 2);
+assert( (boolean) eq2.invokeExact(new Object[]{ "me", "me" }));
+assert(!(boolean) eq2.invokeExact(new Object[]{ "me", "thee" }));
+// spread both arguments from a String array:
+MethodHandle eq2s = equals.asSpreader(String[].class, 2);
+assert( (boolean) eq2s.invokeExact(new String[]{ "me", "me" }));
+assert(!(boolean) eq2s.invokeExact(new String[]{ "me", "thee" }));
+// spread second arguments from a 1-array:
+MethodHandle eq1 = equals.asSpreader(Object[].class, 1);
+assert( (boolean) eq1.invokeExact("me", new Object[]{ "me" }));
+assert(!(boolean) eq1.invokeExact("me", new Object[]{ "thee" }));
+// spread no arguments from a 0-array or null:
+MethodHandle eq0 = equals.asSpreader(Object[].class, 0);
+assert( (boolean) eq0.invokeExact("me", (Object)"me", new Object[0]));
+assert(!(boolean) eq0.invokeExact("me", (Object)"thee", (Object[])null));
+// asSpreader and asCollector are approximate inverses:
+for (int n = 0; n <= 2; n++) {
+ for (Class<?> a : new Class<?>[]{Object[].class, String[].class, CharSequence[].class}) {
+ MethodHandle equals2 = equals.asSpreader(a, n).asCollector(a, n);
+ assert( (boolean) equals2.invokeWithArguments("me", "me"));
+ assert(!(boolean) equals2.invokeWithArguments("me", "thee"));
+ }
+}
+MethodHandle caToString = publicLookup()
+ .findStatic(Arrays.class, "toString", methodType(String.class, char[].class));
+assertEquals("[A, B, C]", (String) caToString.invokeExact("ABC".toCharArray()));
+MethodHandle caString3 = caToString.asCollector(char[].class, 3);
+assertEquals("[A, B, C]", (String) caString3.invokeExact('A', 'B', 'C'));
+MethodHandle caToString2 = caString3.asSpreader(char[].class, 2);
+assertEquals("[A, B, C]", (String) caToString2.invokeExact('A', "BC".toCharArray()));
+ }}
+ }
+
+ @Test public void testAsCollector() throws Throwable {
+ {{
+{} /// JAVADOC
+MethodHandle deepToString = publicLookup()
+ .findStatic(Arrays.class, "deepToString", methodType(String.class, Object[].class));
+assertEquals("[won]", (String) deepToString.invokeExact(new Object[]{"won"}));
+MethodHandle ts1 = deepToString.asCollector(Object[].class, 1);
+assertEquals(methodType(String.class, Object.class), ts1.type());
+//assertEquals("[won]", (String) ts1.invokeExact( new Object[]{"won"})); //FAIL
+assertEquals("[[won]]", (String) ts1.invokeExact((Object) new Object[]{"won"}));
+// arrayType can be a subtype of Object[]
+MethodHandle ts2 = deepToString.asCollector(String[].class, 2);
+assertEquals(methodType(String.class, String.class, String.class), ts2.type());
+assertEquals("[two, too]", (String) ts2.invokeExact("two", "too"));
+MethodHandle ts0 = deepToString.asCollector(Object[].class, 0);
+assertEquals("[]", (String) ts0.invokeExact());
+// collectors can be nested, Lisp-style
+MethodHandle ts22 = deepToString.asCollector(Object[].class, 3).asCollector(String[].class, 2);
+assertEquals("[A, B, [C, D]]", ((String) ts22.invokeExact((Object)'A', (Object)"B", "C", "D")));
+// arrayType can be any primitive array type
+MethodHandle bytesToString = publicLookup()
+ .findStatic(Arrays.class, "toString", methodType(String.class, byte[].class))
+ .asCollector(byte[].class, 3);
+assertEquals("[1, 2, 3]", (String) bytesToString.invokeExact((byte)1, (byte)2, (byte)3));
+MethodHandle longsToString = publicLookup()
+ .findStatic(Arrays.class, "toString", methodType(String.class, long[].class))
+ .asCollector(long[].class, 1);
+assertEquals("[123]", (String) longsToString.invokeExact((long)123));
+ }}
+ }
+
@Test public void testAsVarargsCollector() throws Throwable {
{{
{} /// JAVADOC
+MethodHandle deepToString = publicLookup()
+ .findStatic(Arrays.class, "deepToString", methodType(String.class, Object[].class));
+MethodHandle ts1 = deepToString.asVarargsCollector(Object[].class);
+assertEquals("[won]", (String) ts1.invokeExact( new Object[]{"won"}));
+assertEquals("[won]", (String) ts1.invoke( new Object[]{"won"}));
+assertEquals("[won]", (String) ts1.invoke( "won" ));
+assertEquals("[[won]]", (String) ts1.invoke((Object) new Object[]{"won"}));
+// findStatic of Arrays.asList(...) produces a variable arity method handle:
MethodHandle asList = publicLookup()
- .findStatic(Arrays.class, "asList", methodType(List.class, Object[].class))
- .asVarargsCollector(Object[].class);
+ .findStatic(Arrays.class, "asList", methodType(List.class, Object[].class));
+assertEquals(methodType(List.class, Object[].class), asList.type());
+assert(asList.isVarargsCollector());
assertEquals("[]", asList.invoke().toString());
assertEquals("[1]", asList.invoke(1).toString());
assertEquals("[two, too]", asList.invoke("two", "too").toString());
-Object[] argv = { "three", "thee", "tee" };
+String[] argv = { "three", "thee", "tee" };
assertEquals("[three, thee, tee]", asList.invoke(argv).toString());
+assertEquals("[three, thee, tee]", asList.invoke((Object[])argv).toString());
List ls = (List) asList.invoke((Object)argv);
assertEquals(1, ls.size());
assertEquals("[three, thee, tee]", Arrays.toString((Object[])ls.get(0)));
}}
}
- @Test public void testVarargsCollectorSuppression() throws Throwable {
+ @Test public void testAsFixedArity() throws Throwable {
{{
{} /// JAVADOC
-MethodHandle vamh = publicLookup()
+MethodHandle asListVar = publicLookup()
.findStatic(Arrays.class, "asList", methodType(List.class, Object[].class))
.asVarargsCollector(Object[].class);
-MethodHandle mh = MethodHandles.exactInvoker(vamh.type()).bindTo(vamh);
-assert(vamh.type().equals(mh.type()));
-assertEquals("[1, 2, 3]", vamh.invoke(1,2,3).toString());
-boolean failed = false;
-try { mh.invoke(1,2,3); }
-catch (WrongMethodTypeException ex) { failed = true; }
-assert(failed);
+MethodHandle asListFix = asListVar.asFixedArity();
+assertEquals("[1]", asListVar.invoke(1).toString());
+Exception caught = null;
+try { asListFix.invoke((Object)1); }
+catch (Exception ex) { caught = ex; }
+assert(caught instanceof ClassCastException);
+assertEquals("[two, too]", asListVar.invoke("two", "too").toString());
+try { asListFix.invoke("two", "too"); }
+catch (Exception ex) { caught = ex; }
+assert(caught instanceof WrongMethodTypeException);
+Object[] argv = { "three", "thee", "tee" };
+assertEquals("[three, thee, tee]", asListVar.invoke(argv).toString());
+assertEquals("[three, thee, tee]", asListFix.invoke(argv).toString());
+assertEquals(1, ((List) asListVar.invoke((Object)argv)).size());
+assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString());
+ }}
+ }
+
+ @Test public void testAsTypeCornerCases() throws Throwable {
+ {{
+{} /// JAVADOC
+MethodHandle i2s = publicLookup()
+ .findVirtual(Integer.class, "toString", methodType(String.class));
+i2s = i2s.asType(i2s.type().unwrap());
+MethodHandle l2s = publicLookup()
+ .findVirtual(Long.class, "toString", methodType(String.class));
+l2s = l2s.asType(l2s.type().unwrap());
+
+Exception caught = null;
+try { i2s.asType(methodType(String.class, String.class)); }
+catch (Exception ex) { caught = ex; }
+assert(caught instanceof WrongMethodTypeException);
+
+i2s.asType(methodType(String.class, byte.class));
+i2s.asType(methodType(String.class, Byte.class));
+i2s.asType(methodType(String.class, Character.class));
+i2s.asType(methodType(String.class, Integer.class));
+l2s.asType(methodType(String.class, byte.class));
+l2s.asType(methodType(String.class, Byte.class));
+l2s.asType(methodType(String.class, Character.class));
+l2s.asType(methodType(String.class, Integer.class));
+l2s.asType(methodType(String.class, Long.class));
+
+caught = null;
+try { i2s.asType(methodType(String.class, Long.class)); }
+catch (Exception ex) { caught = ex; }
+assert(caught instanceof WrongMethodTypeException);
+
+MethodHandle i2sGen = i2s.asType(methodType(String.class, Object.class));
+MethodHandle l2sGen = l2s.asType(methodType(String.class, Object.class));
+
+i2sGen.invoke(42); // int -> Integer -> Object -> Integer -> int
+i2sGen.invoke((byte)4); // byte -> Byte -> Object -> Byte -> byte -> int
+l2sGen.invoke(42); // int -> Integer -> Object -> Integer -> int
+l2sGen.invoke((byte)4); // byte -> Byte -> Object -> Byte -> byte -> int
+l2sGen.invoke(0x420000000L);
+
+caught = null;
+try { i2sGen.invoke(0x420000000L); } // long -> Long -> Object -> Integer CCE
+catch (Exception ex) { caught = ex; }
+assert(caught instanceof ClassCastException);
+
+caught = null;
+try { i2sGen.invoke("asdf"); } // String -> Object -> Integer CCE
+catch (Exception ex) { caught = ex; }
+assert(caught instanceof ClassCastException);
{}
}}
}
+
+ @Test public void testMutableCallSite() throws Throwable {
+ {{
+{} /// JAVADOC
+MutableCallSite name = new MutableCallSite(MethodType.methodType(String.class));
+MethodHandle MH_name = name.dynamicInvoker();
+MethodType MT_str1 = MethodType.methodType(String.class);
+MethodHandle MH_upcase = MethodHandles.lookup()
+ .findVirtual(String.class, "toUpperCase", MT_str1);
+MethodHandle worker1 = MethodHandles.filterReturnValue(MH_name, MH_upcase);
+name.setTarget(MethodHandles.constant(String.class, "Rocky"));
+assertEquals("ROCKY", (String) worker1.invokeExact());
+name.setTarget(MethodHandles.constant(String.class, "Fred"));
+assertEquals("FRED", (String) worker1.invokeExact());
+// (mutation can be continued indefinitely)
+/*
+ * </pre></blockquote>
+ * <p>
+ * The same call site may be used in several places at once.
+ * <blockquote><pre>
+ */
+MethodType MT_str2 = MethodType.methodType(String.class, String.class);
+MethodHandle MH_cat = lookup().findVirtual(String.class,
+ "concat", methodType(String.class, String.class));
+MethodHandle MH_dear = MethodHandles.insertArguments(MH_cat, 1, ", dear?");
+MethodHandle worker2 = MethodHandles.filterReturnValue(MH_name, MH_dear);
+assertEquals("Fred, dear?", (String) worker2.invokeExact());
+name.setTarget(MethodHandles.constant(String.class, "Wilma"));
+assertEquals("WILMA", (String) worker1.invokeExact());
+assertEquals("Wilma, dear?", (String) worker2.invokeExact());
+{}
+ }}
+ }
+
+ @Test public void testSwitchPoint() throws Throwable {
+ {{
+{} /// JAVADOC
+MethodHandle MH_strcat = MethodHandles.lookup()
+ .findVirtual(String.class, "concat", MethodType.methodType(String.class, String.class));
+SwitchPoint spt = new SwitchPoint();
+assert(spt.isValid());
+// the following steps may be repeated to re-use the same switch point:
+MethodHandle worker1 = MH_strcat;
+MethodHandle worker2 = MethodHandles.permuteArguments(MH_strcat, MH_strcat.type(), 1, 0);
+MethodHandle worker = spt.guardWithTest(worker1, worker2);
+assertEquals("method", (String) worker.invokeExact("met", "hod"));
+SwitchPoint.invalidateAll(new SwitchPoint[]{ spt });
+assert(!spt.isValid());
+assertEquals("hodmet", (String) worker.invokeExact("met", "hod"));
+{}
+ }}
+ }
+
+ /* ---- TEMPLATE ----
+ @Test public void testFoo() throws Throwable {
+ {{
+{} /// JAVADOC
+{}
+ }}
+ }
+ */
}
diff --git a/test/java/lang/invoke/MethodHandlesTest.java b/test/java/lang/invoke/MethodHandlesTest.java
index ded00ae..1fd6a5c 100644
--- a/test/java/lang/invoke/MethodHandlesTest.java
+++ b/test/java/lang/invoke/MethodHandlesTest.java
@@ -100,6 +100,31 @@
// ValueConversions.varargsArray: UnsupportedOperationException: NYI: cannot form a varargs array of length 13
testInsertArguments(0, 0, MAX_ARG_INCREASE+10);
}
+ @Test @Ignore("permuteArguments has trouble with double slots")
+ public void testFail_7() throws Throwable {
+ testPermuteArguments(new Object[]{10, 200L},
+ new Class<?>[]{Integer.class, long.class},
+ new int[]{1,0});
+ testPermuteArguments(new Object[]{10, 200L, 5000L},
+ new Class<?>[]{Integer.class, long.class, long.class},
+ new int[]{2,0,1}); //rot
+ testPermuteArguments(new Object[]{10, 200L, 5000L},
+ new Class<?>[]{Integer.class, long.class, long.class},
+ new int[]{1,2,0}); //rot
+ testPermuteArguments(new Object[]{10, 200L, 5000L},
+ new Class<?>[]{Integer.class, long.class, long.class},
+ new int[]{2,1,0}); //swap
+ testPermuteArguments(new Object[]{10, 200L, 5000L},
+ new Class<?>[]{Integer.class, long.class, long.class},
+ new int[]{0,1,2,2}); //dup
+ testPermuteArguments(new Object[]{10, 200L, 5000L},
+ new Class<?>[]{Integer.class, long.class, long.class},
+ new int[]{2,0,1,2});
+ testPermuteArguments(new Object[]{10, 200L, 5000L},
+ new Class<?>[]{Integer.class, long.class, long.class},
+ new int[]{2,2,0,1});
+ testPermuteArguments(4, Integer.class, 2, long.class, 6);
+ }
static final int MAX_ARG_INCREASE = 3;
public MethodHandlesTest() {
@@ -356,7 +381,7 @@
ArrayList<Class<?>> argTypes = new ArrayList<Class<?>>(targetType.parameterList());
Collections.fill(argTypes.subList(beg, end), argType);
MethodType ttype2 = MethodType.methodType(targetType.returnType(), argTypes);
- return MethodHandles.convertArguments(target, ttype2);
+ return target.asType(ttype2);
}
// This lookup is good for all members in and under MethodHandlesTest.
@@ -1005,13 +1030,13 @@
Class<?> vtype = ftype;
if (ftype != int.class) vtype = Object.class;
if (isGetter) {
- mh = MethodHandles.convertArguments(mh, mh.type().generic()
- .changeReturnType(vtype));
+ mh = mh.asType(mh.type().generic()
+ .changeReturnType(vtype));
} else {
int last = mh.type().parameterCount() - 1;
- mh = MethodHandles.convertArguments(mh, mh.type().generic()
- .changeReturnType(void.class)
- .changeParameterType(last, vtype));
+ mh = mh.asType(mh.type().generic()
+ .changeReturnType(void.class)
+ .changeParameterType(last, vtype));
}
if (f != null && f.getDeclaringClass() == HasFields.class) {
assertEquals(f.get(fields), value); // clean to start with
@@ -1139,7 +1164,7 @@
// FIXME: change Integer.class and (Integer) below to int.class and (int) below.
MethodType gtype = mh.type().generic().changeParameterType(1, Integer.class);
if (testSetter) gtype = gtype.changeReturnType(void.class);
- mh = MethodHandles.convertArguments(mh, gtype);
+ mh = mh.asType(gtype);
}
Object sawValue, expValue;
List<Object> model = array2list(array);
@@ -1233,11 +1258,10 @@
}
void testConvert(MethodHandle id, Class<?> rtype, String name, Class<?>... params) throws Throwable {
- testConvert(true, false, id, rtype, name, params);
- testConvert(true, true, id, rtype, name, params);
+ testConvert(true, id, rtype, name, params);
}
- void testConvert(boolean positive, boolean useAsType,
+ void testConvert(boolean positive,
MethodHandle id, Class<?> rtype, String name, Class<?>... params) throws Throwable {
countTest(positive);
MethodType idType = id.type();
@@ -1265,10 +1289,7 @@
MethodHandle target = null;
RuntimeException error = null;
try {
- if (useAsType)
- target = id.asType(newType);
- else
- target = MethodHandles.convertArguments(id, newType);
+ target = id.asType(newType);
} catch (RuntimeException ex) {
error = ex;
}
@@ -1293,11 +1314,11 @@
MethodType.methodType(Object.class, String.class, Object[].class));
vac0 = vac0.bindTo("vac");
MethodHandle vac = vac0.asVarargsCollector(Object[].class);
- testConvert(true, true, vac.asType(MethodType.genericMethodType(0)), null, "vac");
- testConvert(true, true, vac.asType(MethodType.genericMethodType(0)), null, "vac");
+ testConvert(true, vac.asType(MethodType.genericMethodType(0)), null, "vac");
+ testConvert(true, vac.asType(MethodType.genericMethodType(0)), null, "vac");
for (Class<?> at : new Class[] { Object.class, String.class, Integer.class }) {
- testConvert(true, true, vac.asType(MethodType.genericMethodType(1)), null, "vac", at);
- testConvert(true, true, vac.asType(MethodType.genericMethodType(2)), null, "vac", at, at);
+ testConvert(true, vac.asType(MethodType.genericMethodType(1)), null, "vac", at);
+ testConvert(true, vac.asType(MethodType.genericMethodType(2)), null, "vac", at, at);
}
}
@@ -1306,8 +1327,8 @@
if (CAN_SKIP_WORKING) return;
startTest("permuteArguments");
testPermuteArguments(4, Integer.class, 2, String.class, 0);
- //testPermuteArguments(6, Integer.class, 0, null, 30);
- //testPermuteArguments(4, Integer.class, 1, int.class, 6);
+ testPermuteArguments(6, Integer.class, 0, null, 30);
+ //testPermuteArguments(4, Integer.class, 2, long.class, 6); // FIXME Fail_7
}
public void testPermuteArguments(int max, Class<?> type1, int t2c, Class<?> type2, int dilution) throws Throwable {
if (verbosity >= 2)
@@ -1421,8 +1442,9 @@
}
MethodType inType = MethodType.methodType(Object.class, types);
MethodType outType = MethodType.methodType(Object.class, permTypes);
- MethodHandle target = MethodHandles.convertArguments(varargsList(outargs), outType);
+ MethodHandle target = varargsList(outargs).asType(outType);
MethodHandle newTarget = MethodHandles.permuteArguments(target, inType, reorder);
+ if (verbosity >= 5) System.out.println("newTarget = "+newTarget);
Object result = newTarget.invokeWithArguments(args);
Object expected = Arrays.asList(permArgs);
if (!expected.equals(result)) {
@@ -1666,7 +1688,7 @@
countTest();
MethodHandle target = varargsList(nargs);
MethodHandle filter = varargsList(1);
- filter = MethodHandles.convertArguments(filter, filter.type().generic());
+ filter = filter.asType(filter.type().generic());
Object[] argsToPass = randomArgs(nargs, Object.class);
if (verbosity >= 3)
System.out.println("filter "+target+" at "+pos+" with "+filter);
@@ -1807,7 +1829,7 @@
// generic invoker
countTest();
inv = MethodHandles.invoker(type);
- if (nargs <= 3) {
+ if (nargs <= 3 && type == type.generic()) {
calledLog.clear();
switch (nargs) {
case 0:
@@ -1833,10 +1855,16 @@
// varargs invoker #0
calledLog.clear();
inv = MethodHandles.spreadInvoker(type, 0);
- result = inv.invokeExact(target, args);
+ if (type.returnType() == Object.class) {
+ result = inv.invokeExact(target, args);
+ } else if (type.returnType() == void.class) {
+ result = null; inv.invokeExact(target, args);
+ } else {
+ result = inv.invokeWithArguments(target, (Object) args);
+ }
if (testRetCode) assertEquals(code, result);
assertCalled("invokee", args);
- if (nargs >= 1) {
+ if (nargs >= 1 && type == type.generic()) {
// varargs invoker #1
calledLog.clear();
inv = MethodHandles.spreadInvoker(type, 1);
@@ -1844,7 +1872,7 @@
if (testRetCode) assertEquals(code, result);
assertCalled("invokee", args);
}
- if (nargs >= 2) {
+ if (nargs >= 2 && type == type.generic()) {
// varargs invoker #2
calledLog.clear();
inv = MethodHandles.spreadInvoker(type, 2);
@@ -1852,7 +1880,7 @@
if (testRetCode) assertEquals(code, result);
assertCalled("invokee", args);
}
- if (nargs >= 3) {
+ if (nargs >= 3 && type == type.generic()) {
// varargs invoker #3
calledLog.clear();
inv = MethodHandles.spreadInvoker(type, 3);
@@ -1865,6 +1893,10 @@
countTest();
calledLog.clear();
inv = MethodHandles.spreadInvoker(type, k);
+ MethodType expType = (type.dropParameterTypes(k, nargs)
+ .appendParameterTypes(Object[].class)
+ .insertParameterTypes(0, MethodHandle.class));
+ assertEquals(expType, inv.type());
List<Object> targetPlusVarArgs = new ArrayList<Object>(targetPlusArgs);
List<Object> tailList = targetPlusVarArgs.subList(1+k, 1+nargs);
Object[] tail = tailList.toArray();
@@ -2045,7 +2077,7 @@
//System.out.println("throwing with "+target+" : "+thrown);
MethodType expectedType = MethodType.methodType(returnType, exType);
assertEquals(expectedType, target.type());
- target = MethodHandles.convertArguments(target, target.type().generic());
+ target = target.asType(target.type().generic());
Throwable caught = null;
try {
Object res = target.invokeExact((Object) thrown);
@@ -2117,12 +2149,12 @@
if (mode.endsWith("/return")) {
if (mode.equals("unbox/return")) {
// fail on return to ((Integer)surprise).intValue
- surprise = MethodHandles.convertArguments(surprise, MethodType.methodType(int.class, Object.class));
- identity = MethodHandles.convertArguments(identity, MethodType.methodType(int.class, Object.class));
+ surprise = surprise.asType(MethodType.methodType(int.class, Object.class));
+ identity = identity.asType(MethodType.methodType(int.class, Object.class));
} else if (mode.equals("cast/return")) {
// fail on return to (Integer)surprise
- surprise = MethodHandles.convertArguments(surprise, MethodType.methodType(Integer.class, Object.class));
- identity = MethodHandles.convertArguments(identity, MethodType.methodType(Integer.class, Object.class));
+ surprise = surprise.asType(MethodType.methodType(Integer.class, Object.class));
+ identity = identity.asType(MethodType.methodType(Integer.class, Object.class));
}
} else if (mode.endsWith("/argument")) {
MethodHandle callee = null;
@@ -2134,14 +2166,14 @@
callee = Surprise.BOX_IDENTITY;
}
if (callee != null) {
- callee = MethodHandles.convertArguments(callee, MethodType.genericMethodType(1));
+ callee = callee.asType(MethodType.genericMethodType(1));
surprise = MethodHandles.filterArguments(callee, 0, surprise);
identity = MethodHandles.filterArguments(callee, 0, identity);
}
}
assertNotSame(mode, surprise, surprise0);
- identity = MethodHandles.convertArguments(identity, MethodType.genericMethodType(1));
- surprise = MethodHandles.convertArguments(surprise, MethodType.genericMethodType(1));
+ identity = identity.asType(MethodType.genericMethodType(1));
+ surprise = surprise.asType(MethodType.genericMethodType(1));
Object x = 42;
for (int i = 0; i < okCount; i++) {
Object y = identity.invokeExact(x);
@@ -2230,14 +2262,14 @@
{
MethodType mt = MethodType.methodType(void.class);
MethodHandle mh = lookup.findStatic(MethodHandlesTest.class, "runForRunnable", mt);
- Runnable proxy = MethodHandles.asInstance(mh, Runnable.class);
+ Runnable proxy = MethodHandleProxies.asInterfaceInstance(Runnable.class, mh);
proxy.run();
assertCalled("runForRunnable");
}
{
MethodType mt = MethodType.methodType(Object.class, Fooable.class, Object.class);
MethodHandle mh = lookup.findStatic(MethodHandlesTest.class, "fooForFooable", mt);
- Fooable proxy = MethodHandles.asInstance(mh, Fooable.class);
+ Fooable proxy = MethodHandleProxies.asInterfaceInstance(Fooable.class, mh);
Object[] args = randomArgs(mt.parameterArray());
Object result = proxy.foo((Fooable) args[0], args[1]);
assertCalled("fooForFooable", args);
@@ -2251,7 +2283,7 @@
}) {
MethodHandle mh = MethodHandles.throwException(void.class, Throwable.class);
mh = MethodHandles.insertArguments(mh, 0, ex);
- WillThrow proxy = MethodHandles.asInstance(mh, WillThrow.class);
+ WillThrow proxy = MethodHandleProxies.asInterfaceInstance(WillThrow.class, mh);
try {
proxy.willThrow();
System.out.println("Failed to throw: "+ex);
@@ -2279,7 +2311,7 @@
CharSequence.class,
Example.class }) {
try {
- MethodHandles.asInstance(varargsArray(0), nonSAM);
+ MethodHandleProxies.asInterfaceInstance(nonSAM, varargsArray(0));
System.out.println("Failed to throw");
assertTrue(false);
} catch (IllegalArgumentException ex) {
diff --git a/test/java/lang/invoke/indify/Indify.java b/test/java/lang/invoke/indify/Indify.java
index 6c0661d..caa0820 100644
--- a/test/java/lang/invoke/indify/Indify.java
+++ b/test/java/lang/invoke/indify/Indify.java
@@ -524,6 +524,8 @@
if (verifySpecifierCount >= 0) {
List<Object[]> specs = bootstrapMethodSpecifiers(false);
int specsLen = (specs == null ? 0 : specs.size());
+ // Pass by specsLen == 0, to help with associated (inner) classes.
+ if (specsLen == 0) specsLen = verifySpecifierCount;
if (specsLen != verifySpecifierCount) {
throw new IllegalArgumentException("BootstrapMethods length is "+specsLen+" but should be "+verifySpecifierCount);
}