meth: {permute,filter}Arguments, {exact,generic,varargs,dynamic}invoker
authorjrose
Fri Jun 19 03:03:53 2009 -0700 (5 months ago)
changeset 467fcc74c8bf23
parent 458592d842cc37
child 47006368c1d475
meth: {permute,filter}Arguments, {exact,generic,varargs,dynamic}invoker
indy.patch
--- a/indy.patch Wed Jun 17 15:56:53 2009 -0700
+++ b/indy.patch Fri Jun 19 03:03:53 2009 -0700
@@ -3,16 +3,17 @@ diff --git a/src/share/classes/java/dyn/
diff --git a/src/share/classes/java/dyn/CallSite.java b/src/share/classes/java/dyn/CallSite.java
--- a/src/share/classes/java/dyn/CallSite.java
+++ b/src/share/classes/java/dyn/CallSite.java
-@@ -26,6 +26,8 @@
+@@ -26,6 +26,9 @@
package java.dyn;
import sun.dyn.util.BytecodeName;
+import sun.dyn.Access;
+import sun.dyn.CallSiteImpl;
++import sun.dyn.MethodHandleImpl;
/**
* An {@code invokedynamic} call site, as reified by the
-@@ -52,15 +54,25 @@
+@@ -52,15 +55,25 @@
* @see Linkage#registerBootstrapMethod(java.lang.Class, java.dyn.MethodHandle)
* @author John Rose, JSR 292 EG
*/
@@ -40,7 +41,7 @@ diff --git a/src/share/classes/java/dyn/
/**
* Make a call site given the parameters from a call to the bootstrap method.
-@@ -72,16 +84,21 @@
+@@ -72,16 +85,21 @@
* @param type the method handle type derived from descriptor of the {@code invokedynamic} instruction
*/
public CallSite(Object caller, String name, MethodType type) {
@@ -67,7 +68,7 @@ diff --git a/src/share/classes/java/dyn/
}
/**
-@@ -102,10 +119,11 @@
+@@ -102,10 +120,11 @@
/**
* Report the current linkage state of the call site. (This is mutable.)
@@ -83,7 +84,7 @@ diff --git a/src/share/classes/java/dyn/
* <p>
* The interactions of {@code getTarget} with memory are the same
* as of a read from an ordinary variable, such as an array element or a
-@@ -118,7 +136,7 @@
+@@ -118,7 +137,7 @@
* @see #setTarget
*/
public MethodHandle getTarget() {
@@ -92,7 +93,7 @@ diff --git a/src/share/classes/java/dyn/
}
/**
-@@ -140,7 +158,7 @@
+@@ -140,7 +159,7 @@
*/
public void setTarget(MethodHandle target) {
checkTarget(target);
@@ -101,30 +102,33 @@ diff --git a/src/share/classes/java/dyn/
}
protected void checkTarget(MethodHandle target) {
-@@ -219,6 +237,6 @@
+@@ -219,6 +238,10 @@
@Override
public String toString() {
- return "CallSite#"+hashCode()+"["+name+type+" => "+target+"]";
+ return "CallSite#"+hashCode()+"["+name+type+" => "+getTarget()+"]";
}
++
++ // Package-local constant:
++ static final MethodHandle GET_TARGET = MethodHandleImpl.getLookup(IMPL_TOKEN).
++ findVirtual(CallSite.class, "getTarget", MethodType.make(MethodHandle.class));
}
diff --git a/src/share/classes/java/dyn/InvokeDynamic.java b/src/share/classes/java/dyn/InvokeDynamic.java
--- a/src/share/classes/java/dyn/InvokeDynamic.java
+++ b/src/share/classes/java/dyn/InvokeDynamic.java
-@@ -45,6 +45,23 @@
+@@ -45,6 +45,24 @@
* class or interface supertype, or an object type; it can never be instantiated.
* Logically, it denotes a source of all dynamically typed methods.
* It may be viewed as a pure syntactic marker (an importable one) of static calls.
+ * <p>
-+ * Example of use:
-+ * <blockquote><pre>
-+ * Object x, y; String s; int i;
++ * Here are some examples of usage:
++ * <p><blockquote><pre>
++ * Object x; String s; int i;
+ * x = InvokeDynamic.greet("world"); // greet(Ljava/lang/String;)Ljava/lang/Object;
-+ * y = "world";
+ * s = InvokeDynamic.&lt;String&gt;hail(x); // hail(Ljava/lang/Object;)Ljava/lang/String;
+ * InvokeDynamic.&lt;void&gt;cogito(); // cogito()V
-+ * i = InvokeDynamic.&lt;int&gt;#"op:+"(2, 3); // +(II)I
++ * i = InvokeDynamic.&lt;int&gt;#"op:+"(2, 3); // "op:+"(II)I
+ * </pre></blockquote>
+ * Each of the above calls generates a single invokedynamic instruction
+ * with the name-and-type descriptors indicated in the comments.
@@ -133,6 +137,8 @@ diff --git a/src/share/classes/java/dyn/
+ * (This type parameter may be a primtive, and it defaults to {@code Object}.)
+ * The final example uses a special syntax for uttering non-Java names.
+ * Any name legal to the JVM may be given between the double quotes.
++ * None of these calls is complete without a bootstrap method,
++ * which must be registered by the static initializer of the enclosing class.
* @author John Rose, JSR 292 EG
*/
public final class InvokeDynamic {
@@ -155,6 +161,147 @@ diff --git a/src/share/classes/java/dyn/
+ super(s);
+ this.initCause(cause);
+ }
+ }
+diff --git a/src/share/classes/java/dyn/JavaMethodHandle.java b/src/share/classes/java/dyn/JavaMethodHandle.java
+--- a/src/share/classes/java/dyn/JavaMethodHandle.java
++++ b/src/share/classes/java/dyn/JavaMethodHandle.java
+@@ -25,6 +25,8 @@
+
+ package java.dyn;
+
++import sun.dyn.Access;
++
+ /**
+ * A Java method handle extends the basic method handle type with additional
+ * programmer defined methods and fields.
+@@ -41,29 +43,43 @@
+ * <p>
+ * Here is an example of usage:
+ * <p><blockquote><pre>
+- * class Greeter extends JavaMethodHandle {
+- * public void run() { System.out.println("hello, "+greetee); }
+- * private final String greetee;
+- * Greeter(String greetee) {
+- * super(RUN);
+- * this.greetee = greetee;
+- * }
+- * // the entry point function is computed once:
+- * private static final MethodHandle RUN
+- * = MethodHandles.findVirtual(MyMethodHandle.class, "run",
+- * MethodType.make(void.class));
++ * class Greeter extends JavaMethodHandle {
++ * public void run() { System.out.println("hello, "+greetee); }
++ * private final String greetee;
++ * Greeter(String greetee) {
++ * super(RUN); // alternatively, super("run")
++ * this.greetee = greetee;
+ * }
+- * Greeter greeter = new Greeter("world");
+- * greeter.run(); // prints "hello, world"
+- * MethodHandle mh = greeter;
+- * mh.invoke(); // also prints "hello, world"
++ * // the entry point function is computed once:
++ * private static final MethodHandle RUN
++ * = MethodHandles.lookup().findVirtual(Greeter.class, "run",
++ * MethodType.make(void.class));
++ * }
++ * Greeter greeter = new Greeter("world");
++ * greeter.run(); // prints "hello, world"
++ * // Statically typed method handle invocation (most direct):
++ * MethodHandle mh = greeter;
++ * mh.&lt;void&gt;invoke(); // also prints "hello, world"
++ * // Dynamically typed method handle invocation:
++ * MethodHandles.invoke(greeter); // also prints "hello, world"
+ * </pre></blockquote>
+ * <p>
+- * In this example, the method {@code run} provides the entry point.
++ * In the example of {@code Greeter}, the method {@code run} provides the entry point.
+ * The entry point need not be a constant value; it may be independently
+ * computed in each call to the constructor. The entry point does not
+- * even need to be a method on the Java method handle class, though
++ * even need to be a method on the {@code Greeter} class, though
+ * that is the typical case.
++ * <p>
++ * The entry point may also be provided symbolically, in which case the the
++ * {@code JavaMethodHandle} constructor performs the lookup of the entry point.
++ * This makes it possible to use {@code JavaMethodHandle} to create an anonymous
++ * inner class:
++ * <p><blockquote><pre>
++ * // We can also do this with symbolic names and/or inner classes:
++ * MethodHandles.invoke(new JavaMethodHandle("yow") {
++ * void yow() { System.out.println("yow, world"); }
++ * });
++ * </pre></blockquote>
+ * @see MethodHandle
+ * @author John Rose, JSR 292 EG
+ */
+@@ -72,12 +88,63 @@
+ // with a JVM change which moves the required hidden behavior onto this class.
+ extends sun.dyn.BoundMethodHandle
+ {
++ private static final Access IMPL_TOKEN = Access.getToken();
++
+ /**
+- * When creating a, pass in {@code entryPoint}, any method handle which
+- * can take the current object
+- * @param entryPoint
++ * When creating a {@code JavaMethodHandle}, the actual method handle
++ * invocation behavior will be delegated to the specified {@code entryPoint}.
++ * This may be any method handle which can take the newly constructed object
++ * as a leading parameter.
++ * <p>
++ * The method handle type of {@code this} (i.e, the fully constructed object)
++ * will be {@code entryPoint}, minus the leading argument.
++ * The leading argument will be bound to {@code this} on every method
++ * handle invocation.
++ * @param entryPoint the method handle to handle calls
+ */
+ protected JavaMethodHandle(MethodHandle entryPoint) {
+- super(entryPoint, 0);
++ super(entryPoint);
++ }
++
++ /**
++ * Create a method handle whose entry point is a non-static method
++ * callable from the exact (most specific) class of the newly constructed
++ * object. The method is specified only by name and arity.
++ * Of all the methods visible to the object class,
++ * either inherited or locally declared, there must be
++ * exactly one method with the given name and same number of arguments
++ * as the requested method type.
++ * <p>
++ * The method handle type of {@code this} (i.e, the fully constructed object)
++ * will be the given method handle type.
++ * A call to {@code this} will invoke the selected method,
++ * with any necessary conversions from the given type,
++ * as defined by {@link MethodHandles.convertArguments}.
++ * The receiver argument will be bound to {@code this} on every method
++ * handle invocation.
++ * @param entryPointName the name of the entry point method
++ * @param type (optional) the desired type of the method handle
++ */
++ protected JavaMethodHandle(String entryPointName, MethodType type) {
++ super(entryPointName, type, true);
++
++ }
++
++ /**
++ * Create a method handle whose entry point is a non-static method
++ * callable from the exact (most specific) class of the newly constructed
++ * object. The method is specified only by name.
++ * There must be exactly one method of that name visible to the object class,
++ * either inherited or locally declared.
++ * (That is, the method must not be overloaded.)
++ * <p>
++ * The method handle type of {@code this} (i.e, the fully constructed object)
++ * will be the same as the selected non-static method.
++ * The receiver argument will be bound to {@code this} on every method
++ * handle invocation.
++ * @param entryPointName the name of the entry point method
++ */
++ protected JavaMethodHandle(String entryPointName) {
++ super(entryPointName, (MethodType) null, false);
+ }
}
diff --git a/src/share/classes/java/dyn/Linkage.java b/src/share/classes/java/dyn/Linkage.java
--- a/src/share/classes/java/dyn/Linkage.java
@@ -307,8 +454,8 @@ diff --git a/src/share/classes/java/dyn/
* receiver type. Such a method handle simulates the effect of
* an <code>invokespecial</code> instruction to the same method.
+ * <p>
-+ * Example of use:
-+ * <blockquote><pre>
++ * Here are some examples of usage:
++ * <p><blockquote><pre>
+ * Object x, y; String s; int i;
+ * MethodType mt; MethodHandle mh;
+ * MethodHandles.Lookup lookup = MethodHandles.lookup();
@@ -316,13 +463,13 @@ diff --git a/src/share/classes/java/dyn/
+ * mt = MethodType.make(String.class, char.class, char.class);
+ * mh = lookup.findVirtual(String.class, "replace", mt);
+ * // (Ljava/lang/String;CC)Ljava/lang/String;
-+ * s = mh.&lt;String&gt;invoke("would",'u','r');
-+ * assert(s.equals("world"));
++ * s = mh.&lt;String&gt;invoke("daddy",'d','n');
++ * assert(s.equals("nanny"));
+ * // weakly typed invocation (using MHs.invoke)
+ * s = (String) MethodHandles.invoke(mh, "sappy", 'p', 'v');
+ * assert(s.equals("savvy"));
+ * // mt is {Object[] =&gt; List}
-+ * mt = MethodType.make(List.class, Object[].class);
++ * mt = MethodType.make(java.util.List.class, Object[].class);
+ * mh = lookup.findStatic(java.util.Arrays.class, "asList", mt);
+ * // mt is {(Object,Object,Object) =&gt; Object}
+ * mt = MethodType.makeGeneric(3);
@@ -333,7 +480,7 @@ diff --git a/src/share/classes/java/dyn/
+ * assert(x.equals(java.util.Arrays.asList(1,2,3)));
+ * // mt is { =&gt; int}
+ * mt = MethodType.make(int.class);
-+ * mh = lookup.findVirtual(List.class, "size", mt);
++ * mh = lookup.findVirtual(java.util.List.class, "size", mt);
+ * // (Ljava/util/List;)I
+ * i = mh.&lt;int&gt;invoke(java.util.Arrays.asList(1,2,3));
+ * assert(i == 3);
@@ -346,30 +493,60 @@ diff --git a/src/share/classes/java/dyn/
*
* @see MethodType
* @see MethodHandles
-@@ -107,8 +158,8 @@
+@@ -107,10 +158,12 @@
// with a JVM change which moves the required hidden state onto this class.
extends MethodHandleImpl
{
- // interface MethodHandle<T extends MethodType<R,A...>>
- // { T type(); <R,A...> public R invoke(A...); }
++ private static Access IMPL_TOKEN = Access.getToken();
+
+- final private MethodType type;
+ // interface MethodHandle<R throws X extends Exception,A...>
+ // { MethodType<R throws X,A...> type(); public R invoke(A...) throws X; }
-
- final private MethodType type;
-
++
++ private MethodType type;
+
+ /**
+ * Report the type of this method handle.
+@@ -130,6 +183,33 @@
+ */
+ protected MethodHandle(Access token, MethodType type) {
+ super(token);
++ Access.check(token);
+ this.type = type;
+ }
++
++ private void initType(MethodType type) {
++ type.getClass(); // elicit NPE
++ if (this.type != null) throw new InternalError();
++ this.type = type;
++ }
++
++ static {
++ // This hack allows the implementation package special access to
++ // the internals of MethodHandle. In particular, the MTImpl has all sorts
++ // of cached information useful to the implementation code.
++ MethodHandleImpl.setMethodHandleFriend(IMPL_TOKEN, new MethodHandleImpl.MethodHandleFriend() {
++ public void initType(MethodHandle mh, MethodType type) { mh.initType(type); }
++ });
++ }
++
++ /** The string of a direct method handle is the simple name of its target method.
++ * The string of an adapter or bound method handle is the string of its
++ * target method handle.
++ * The string of a Java method handle is the string of its entry point method,
++ * unless the Java method handle overrides the toString method.
++ */
++ @Override
++ public String toString() {
++ return MethodHandleImpl.getNameString(IMPL_TOKEN, this);
++ }
+ }
diff --git a/src/share/classes/java/dyn/MethodHandles.java b/src/share/classes/java/dyn/MethodHandles.java
--- a/src/share/classes/java/dyn/MethodHandles.java
+++ b/src/share/classes/java/dyn/MethodHandles.java
-@@ -36,6 +36,8 @@
- import java.lang.reflect.Modifier;
- import java.util.ArrayList;
- import java.util.Arrays;
-+import java.util.Iterator;
-+import java.util.List;
- import sun.dyn.Invokers;
- import sun.dyn.MethodTypeImpl;
- import sun.reflect.Reflection;
-@@ -53,7 +55,6 @@
+@@ -53,7 +53,6 @@
* Generics are not variadic, and so cannot represent this.</li>
* <li>Method types can specify arguments of primitive types,
* which Java generic types cannot range over.</li>
@@ -377,7 +554,7 @@ diff --git a/src/share/classes/java/dyn/
* </ol>
* @author John Rose, JSR 292 EG
*/
-@@ -68,12 +69,22 @@
+@@ -68,12 +67,22 @@
//// Method handle creation from ordinary methods.
@@ -401,7 +578,7 @@ diff --git a/src/share/classes/java/dyn/
* A factory object for creating method handles, when the creation
* requires access checking. Method handles do not perform
* access checks when they are called; this is a major difference
-@@ -121,7 +132,8 @@
+@@ -121,7 +130,8 @@
/** Which class is performing the lookup? It is this class against
* which checks are performed for visibility and access permissions.
* <p>
@@ -411,7 +588,7 @@ diff --git a/src/share/classes/java/dyn/
*/
public Class<?> lookupClass() {
return lookupClass;
-@@ -135,23 +147,46 @@
+@@ -135,23 +145,46 @@
* an access$N method.
*/
Lookup() {
@@ -463,7 +640,7 @@ diff --git a/src/share/classes/java/dyn/
/** Package-private version of lookup which is trusted. */
static final Lookup IMPL_LOOKUP = new Lookup(null);
-@@ -178,12 +213,16 @@
+@@ -178,12 +211,16 @@
// 0: Reflection.getCC, 1: getCallerClassAtEntryPoint,
// 2: Lookup.<init>, 3: MethodHandles.*, 4: caller
// Note: This should be the only use of getCallerClass in this file.
@@ -480,7 +657,7 @@ diff --git a/src/share/classes/java/dyn/
* The method and all its argument types must be accessible to the lookup class.
* If the method's class has not yet been initialized, that is done
* immediately, before the method handle is returned.
-@@ -196,10 +235,11 @@
+@@ -196,10 +233,11 @@
*/
public
MethodHandle findStatic(Class<?> defc, String name, MethodType type) throws NoAccessException {
@@ -495,7 +672,7 @@ diff --git a/src/share/classes/java/dyn/
}
/**
-@@ -228,9 +268,10 @@
+@@ -228,9 +266,10 @@
* @exception NoAccessException if the method does not exist or access checking fails
*/
public MethodHandle findVirtual(Class<?> defc, String name, MethodType type) throws NoAccessException {
@@ -509,7 +686,7 @@ diff --git a/src/share/classes/java/dyn/
}
/**
-@@ -259,15 +300,17 @@
+@@ -259,15 +298,17 @@
*/
public MethodHandle findSpecial(Class<?> defc, String name, MethodType type,
Class<?> specialCaller) throws NoAccessException {
@@ -532,7 +709,7 @@ diff --git a/src/share/classes/java/dyn/
}
/**
-@@ -275,13 +318,19 @@
+@@ -275,13 +316,19 @@
* The receiver must have a supertype {@code defc} in which a method
* of the given name and type is accessible to the lookup class.
* The method and all its argument types must be accessible to the lookup class.
@@ -556,7 +733,7 @@ diff --git a/src/share/classes/java/dyn/
* @param receiver the object from which the method is accessed
* @param name the name of the method
* @param type the type of the method, with the receiver argument omitted
-@@ -292,16 +341,18 @@
+@@ -292,16 +339,18 @@
public MethodHandle bind(Object receiver, String name, MethodType type) throws NoAccessException {
Class<? extends Object> rcvc = receiver.getClass(); // may get NPE
MemberName reference = new MemberName(rcvc, name, type);
@@ -579,7 +756,7 @@ diff --git a/src/share/classes/java/dyn/
* Make a direct method handle to <i>m</i>, if the lookup class has permission.
* If <i>m</i> is non-static, the receiver argument is treated as an initial argument.
* If <i>m</i> is virtual, overriding is respected on every call.
-@@ -316,10 +367,11 @@
+@@ -316,10 +365,11 @@
* @exception NoAccessException if access checking fails
*/
public MethodHandle unreflect(Method m) throws NoAccessException {
@@ -592,7 +769,7 @@ diff --git a/src/share/classes/java/dyn/
* Produce a method handle for a reflected method.
* It will bypass checks for overriding methods on the receiver,
* as if by the {@code invokespecial} instruction.
-@@ -333,37 +385,41 @@
+@@ -333,37 +383,41 @@
* @exception NoAccessException if access checking fails
*/
public MethodHandle unreflectSpecial(Method m, Class<?> specialCaller) throws NoAccessException {
@@ -643,7 +820,7 @@ diff --git a/src/share/classes/java/dyn/
* If the method's {@code accessible} flag is not set,
* access checking is performed immediately on behalf of the lookup class.
* @param f the reflected field
-@@ -371,16 +427,17 @@
+@@ -371,16 +425,17 @@
* @exception NoAccessException if access checking fails
*/
public MethodHandle unreflectGetter(Field f) throws NoAccessException {
@@ -665,7 +842,7 @@ diff --git a/src/share/classes/java/dyn/
* If the method's {@code accessible} flag is not set,
* access checking is performed immediately on behalf of the lookup class.
* @param f the reflected field
-@@ -388,59 +445,63 @@
+@@ -388,59 +443,63 @@
* @exception NoAccessException if access checking fails
*/
public MethodHandle unreflectSetter(Field f) throws NoAccessException {
@@ -748,7 +925,26 @@ diff --git a/src/share/classes/java/dyn/
}
/**
-@@ -509,51 +570,113 @@
+@@ -472,7 +531,6 @@
+ return MethodHandleImpl.accessArrayElement(IMPL_TOKEN, arrayClass, true);
+ }
+
+-
+ /// method handle invocation (reflective style)
+
+ /**
+@@ -500,110 +558,203 @@
+ * or forced to null if the return type is void.
+ * <p>
+ * This call is a convenience method for the following code:
+- * <pre>
++ * <p><blockquote><pre>
+ * MethodHandle invoker = MethodHandles.genericInvoker(target.type(), 0, true);
+ * Object result = invoker.invoke(arguments);
+- * </pre>
++ * </pre></blockquote>
+ * @param target the method handle to invoke
+ * @param arguments the arguments to pass to the target
* @return the result returned by the target
*/
public static
@@ -756,7 +952,8 @@ diff --git a/src/share/classes/java/dyn/
+ Object invoke(MethodHandle target, Object... arguments) throws Throwable {
int argc = arguments == null ? 0 : arguments.length;
MethodType type = target.type();
- if (argc <= 4) {
+- if (argc <= 4) {
++ if (argc <= 10) {
MethodHandle invoker = invokers(type).genericInvoker();
switch (argc) {
- case 0: return invoker.<Object>invoke(target);
@@ -800,10 +997,11 @@ diff --git a/src/share/classes/java/dyn/
+ arguments[9]);
}
}
+- MethodHandle invoker = invokers(type).varargsInvoker();
+- return invoker.<Object>invoke(target, arguments);
+
+ // more than ten arguments get boxed in a varargs list:
- MethodHandle invoker = invokers(type).varargsInvoker();
-- return invoker.<Object>invoke(target, arguments);
++ MethodHandle invoker = invokers(type).varargsInvoker(0);
+ return invoker.invoke(target, arguments);
}
@@ -880,7 +1078,155 @@ diff --git a/src/share/classes/java/dyn/
}
/**
-@@ -703,26 +826,15 @@
+ * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
+- * Give a method handle which will invoke any method handle of the
++ * Produce a method handle which will invoke any method handle of the
+ * given type on a standard set of {@code Object} type arguments.
+- * The the resulting invoker will be a method handle with the following
++ * The resulting invoker will be a method handle with the following
+ * arguments:
+ * <ul>
+ * <li>a single {@code MethodHandle} target
+- * <li>zero or more {@code Object} values
+- * <li>an optional {@code Object[]} array containing more arguments
++ * <li>zero or more {@code Object} values (one for each argument in {@code type})
+ * </ul>
+- * The invoker will spread the varargs array (if present), apply
++ * The invoker will apply reference casts as necessary and unbox primitive arguments,
++ * as if by {@link #convertArguments}.
++ * The return value of the invoker will be an {@code Object} reference,
++ * boxing a primitive value if the original type returns a primitive,
++ * and always null if the original type returns void.
++ * <p>
++ * This method is equivalent to the following code (though it may be more efficient):
++ * <p><blockquote><pre>
++ * MethodHandle invoker = exactInvoker(type);
++ * MethodType genericType = type.generic();
++ * genericType = genericType.insertParameterType(0, MethodHandle.class);
++ * return convertArguments(invoker, genericType);
++ * </pre></blockquote>
++ * @param type the type of target methods which the invoker will apply to
++ * @return a method handle suitable for invoking any method handle of the given type
++ */
++ static public
++ MethodHandle genericInvoker(MethodType type) {
++ return invokers(type).genericInvoker();
++ }
++
++ /**
++ * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
++ * Produce a method handle which will invoke any method handle of the
++ * given type on a standard set of {@code Object} type arguments
++ * and a single trailing {@code Object[]} array.
++ * The resulting invoker will be a method handle with the following
++ * arguments:
++ * <ul>
++ * <li>a single {@code MethodHandle} target
++ * <li>zero or more {@code Object} values (counted by {@code objectArgCount})
++ * <li>an {@code Object[]} array containing more arguments
++ * </ul>
++ * The invoker will spread the varargs array, apply
+ * reference casts as necessary, and unbox primitive arguments.
+ * The return value of the invoker will be an {@code Object} reference,
+ * boxing a primitive value if the original type returns a primitive,
+ * and always null if the original type returns void.
+ * <p>
+- * This is a convenience method equivalent to the following code:
+- * <pre>
++ * This method is equivalent to the following code (though it may be more efficient):
++ * <p><blockquote><pre>
+ * MethodHandle invoker = exactInvoker(type);
+- * MethodType genericType = MethodType.makeGeneric(objectArgCount, varargs);
+- * genericType = genericType.insertParameterType(0, MethodHandle.class);
+- * if (!varargs)
+- * return convertArguments(invoker, genericType);
+- * else
+- * return spreadArguments(invoker, genericType);
+- * </pre>
++ * MethodType vaType = MethodType.makeGeneric(objectArgCount, true);
++ * vaType = vaType.insertParameterType(0, MethodHandle.class);
++ * return spreadArguments(invoker, vaType);
++ * </pre></blockquote>
+ * @param type the desired target type
+ * @param objectArgCount number of fixed (non-varargs) {@code Object} arguments
+ * @param varargs if true, the invoker will accept a final {@code Object[]} argument
+ * @return a method handle suitable for invoking any method handle of the given type
+ */
+ static public
+- MethodHandle genericInvoker(MethodType type, int objectArgCount, boolean varargs) {
+- return invokers(type).genericInvoker();
++ MethodHandle varargsInvoker(MethodType type, int objectArgCount) {
++ if (objectArgCount < 0 || objectArgCount > type.parameterCount())
++ throw new IllegalArgumentException("bad argument count "+objectArgCount);
++ return invokers(type).varargsInvoker(objectArgCount);
+ }
+
+ /**
+ * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
+- * Give a method handle which will take a invoke any method handle of the
++ * Produce a method handle which will take a invoke any method handle of the
+ * given type. The resulting invoker will have a type which is
+ * exactly equal to the desired type, except that it will accept
+ * an additional leading argument of type {@code MethodHandle}.
+ * <p>
+- * This is a convenience method equivalent to the following code:
+- * <pre>
+- * MethodHandles.lookup().findVirtual(MethodHandle.class, "invoke", type);
+- * </pre>
++ * This method is equivalent to the following code (though it may be more efficient):
++ * <p><blockquote><pre>
++ * lookup().findVirtual(MethodHandle.class, "invoke", type);
++ * </pre></blockquote>
+ * @param type the desired target type
+ * @return a method handle suitable for invoking any method handle of the given type
+ */
+@@ -612,6 +763,29 @@
+ return invokers(type).exactInvoker();
+ }
+
++ /**
++ * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
++ * Produce a method handle equivalent to an invokedynamic instruction
++ * which has been linked to the given call site.
++ * Along with {@link Lookup#findVirtual}, {@link Lookup#findStatic},
++ * and {@link Lookup#findSpecial}, this completes the emulation
++ * of the JVM's {@code invoke} instructions.
++ * <p>This method is equivalent to the following code:
++ * <p><blockquote><pre>
++ * MethodHandle getTarget, invoker, result;
++ * getTarget = lookup().bind(site, "getTarget", methodType(MethodHandle.class));
++ * invoker = exactInvoker(site.type());
++ * result = foldArguments(invoker, getTarget)
++ * </pre></blockquote>
++ * @return a method handle which always invokes the call site's target
++ */
++ public static
++ MethodHandle dynamicInvoker(CallSite site) {
++ MethodHandle getTarget = MethodHandleImpl.bindReceiver(IMPL_TOKEN, CallSite.GET_TARGET, site);
++ MethodHandle invoker = exactInvoker(site.type());
++ return foldArguments(invoker, getTarget);
++ }
++
+ static private Invokers invokers(MethodType type) {
+ return MethodTypeImpl.invokers(IMPL_TOKEN, type);
+ }
+@@ -690,12 +864,10 @@
+ /**
+ * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
+ * Produce a method handle which adapts the type of the
+- * given method handle to a new type, by pairwise argument conversion,
+- * and/or varargs conversion.
+- * The original type and new type must have the same number of
+- * arguments, or else one or both them the must be varargs types.
++ * given method handle to a new type by pairwise argument conversion.
++ * The original type and new type must have the same number of arguments.
+ * The resulting method handle is guaranteed to confess a type
+- * which is equal to the desired new type, with any varargs property erased.
++ * which is equal to the desired new type.
+ * <p>
+ * If the original type and new type are equal, returns target.
+ * <p>
+@@ -703,26 +875,15 @@
* arguments and return types. Let T0 and T1 be the differing
* new and old parameter types (or old and new return types)
* for corresponding values passed by the new and old method types.
@@ -913,7 +1259,7 @@ diff --git a/src/share/classes/java/dyn/
* <li>If T0 and T1 are primitives, then a Java casting
* conversion (JLS 5.5) is applied, if one exists.
* <li>If T0 and T1 are primitives and one is boolean,
-@@ -745,9 +857,9 @@
+@@ -745,9 +906,9 @@
* if necessary to T1 by one of the preceding conversions.
* Otherwise, T0 is converted directly to the wrapper type for T1,
* which is then unboxed.
@@ -926,7 +1272,7 @@ diff --git a/src/share/classes/java/dyn/
* </ul>
* @param target the method handle to invoke after arguments are retyped
* @param newType the expected type of the new method handle
-@@ -872,20 +984,14 @@
+@@ -872,20 +1033,14 @@
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Produce a method handle which adapts the type of the
* given method handle to a new type, by collecting a series of
@@ -949,12 +1295,16 @@ diff --git a/src/share/classes/java/dyn/
* @param target the method handle to invoke after the argument is prepended
* @param newType the expected type of the new method handle
* @return a new method handle which collects some trailings argument
-@@ -900,50 +1006,62 @@
+@@ -900,50 +1055,66 @@
int numCollect = (inargs - collectPos);
if (collectPos < 0 || numCollect < 0)
throw newIllegalArgumentException("wrong number of arguments");
- return MethodHandleImpl.collectArguments(IMPL_TOKEN, target, newType, collectPos);
-+ return MethodHandleImpl.collectArguments(IMPL_TOKEN, target, newType, collectPos, null);
++ MethodHandle res = MethodHandleImpl.collectArguments(IMPL_TOKEN, target, newType, collectPos, null);
++ if (res == null) {
++ throw newIllegalArgumentException("cannot collect from "+newType+" to " +oldType);
++ }
++ return res;
}
/**
@@ -1037,7 +1387,7 @@ diff --git a/src/share/classes/java/dyn/
}
/**
-@@ -953,10 +1071,25 @@
+@@ -953,10 +1124,25 @@
* The type of the new method handle will insert the given argument
* type(s), at that position, into the original handle's type.
* <p>
@@ -1048,7 +1398,7 @@ diff --git a/src/share/classes/java/dyn/
* or an argument somewhere in between.
+ * <p>
+ * <b>Example:</b>
-+ * <pre>
++ * <p><blockquote><pre>
+ * MethodHandle cat = MethodHandles.lookup().
+ * findVirtual(String.class, "concat", String.class, String.class);
+ * System.out.println(cat.&lt;String&gt;invoke("x", "y")); // xy
@@ -1060,81 +1410,78 @@ diff --git a/src/share/classes/java/dyn/
+ * System.out.println(d2.&lt;String&gt;invoke("x", "y", "z")); // yz
+ * MethodHandle d12 = dropArguments(cat, 1, String.class, String.class);
+ * System.out.println(d12.&lt;String&gt;invoke("w", "x", "y", "z")); // wz
-+ * </pre>
++ * </pre></blockquote>
* @param target the method handle to invoke after the argument is dropped
* @param valueTypes the type(s) of the argument to drop
* @param pos which argument to drop (zero for the first)
-@@ -1040,65 +1173,121 @@
+@@ -980,6 +1166,131 @@
/**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
-- * Adapt a target method handle {@code target} by first processing
-- * its arguments, and then calling the target.
-- * The initial processing is performed by a second method handle, the {@code combiner}.
-- * After this, control passes to the {@code target}, with the same arguments.
-+ * Make a method handle which adapts a target method handle,
-+ * by running it inside an exception handler.
-+ * If the target returns normally, the adapter returns that value.
-+ * If an exception matching the specified type is thrown, the fallback
-+ * handle is called instead on the exception, plus the original arguments.
- * <p>
-- * The return value of the {@code combiner} is inserted into the argument list
-- * for the {@code target} at the indicated position {@code pos}, if it is non-negative.
-- * Except for this inserted argument (if any), the argument types of
-- * the target {@code target} and the {@code combiner} must be identical.
-+ * The handler must have leading parameter of {@code exType} or a supertype,
-+ * followed by arguments which correspond <em>(how? TBD)</em> to
-+ * all the parameters of the target.
-+ * The target and handler must return the same type.
++ * Adapt a target method handle {@code target} by pre-processing
++ * one or more of its arguments, each with its own unary filter function,
++ * and then calling the target with each pre-processed argument
++ * replaced by the result of its corresponding filter function.
++ * <p>
++ * The pre-processing is performed by one or more method handles,
++ * specified in the non-null elements of the {@code filters} array.
++ * (If there are no such elements, the original target is returned.)
++ * Each filter (that is, each non-null element of {@code filters})
++ * is applied to the corresponding argument of the adapter.
++ * <p>
++ * If a filter {@code F} applies to the {@code N}th argument of
++ * the method handle, then {@code F} must be a method handle which
++ * takes exactly one argument. The type of {@code F}'s sole argument
++ * replaces the corresponding argument type of the target
++ * in the resulting adapted method handle.
++ * The return type of {@code F} must be identical to the corresponding
++ * parameter type of the target.
++ * <p>
++ * It is an error if there are non-null elements of {@code filters}
++ * which do not correspond to argument positions in the target.
++ * The actual length of the target array may be any number, it need
++ * not be the same as the parameter count of the target type.
++ * (This provides an easy way to filter just the first argument or two
++ * of a target method handle.)
+ * <p> Here is pseudocode for the resulting adapter:
+ * <blockquote><pre>
-+ * T target(A...);
-+ * T handler(ExType, A...);
-+ * T adapter(A... a) {
-+ * try {
-+ * return target(a...);
-+ * } catch (ExType ex) {
-+ * return handler(ex, a...);
-+ * }
++ * // there are N arguments in the A sequence
++ * T target(A[N]...);
++ * [i&lt;N] V[i] filter[i](B[i]) = filters[i] ?: identity;
++ * T adapter(B[N]... b) {
++ * A[N] a...;
++ * [i&lt;N] a[i] = filter[i](b[i]);
++ * return target(a...);
+ * }
+ * </pre></blockquote>
-+ * @param target method handle to call
-+ * @param exType the type of exception which the handler will catch
-+ * @param handler method handle to call if a matching exception is thrown
-+ * @return method handle which incorporates the specified try/catch logic
-+ * @throws IllegalArgumentException if {@code handler} does not accept
-+ * the given exception type, or if the method handle types do
-+ * not match in their return types and their
-+ * corresponding parameters
++ * @param target the method handle to invoke after arguments are filtered
++ * @param filters method handles to call initially on filtered arguments
++ * @return method handle which incorporates the specified argument filtering logic
++ * @throws IllegalArgumentException if a non-null element of {@code filters}
++ * does not match a corresponding argument type of {@code target}
+ */
+ public static
-+ MethodHandle catchException(MethodHandle target,
-+ Class<? extends Throwable> exType,
-+ MethodHandle handler) {
++ MethodHandle filterArguments(MethodHandle target, MethodHandle... filters) {
+ MethodType targetType = target.type();
-+ MethodType handlerType = handler.type();
-+ boolean ok = (targetType.parameterCount() ==
-+ handlerType.parameterCount() - 1);
-+// for (int i = 0; ok && i < numExArgs; i++) {
-+// if (targetType.parameterType(i) != handlerType.parameterType(1+i))
-+// ok = false;
-+// }
-+ if (!ok)
-+ throw newIllegalArgumentException("target and handler types do not match");
-+ return MethodHandleImpl.makeGuardWithCatch(IMPL_TOKEN, target, exType, handler);
-+ }
-+
-+ /**
-+ * Produce a method handle which will throw exceptions of the given {@code exType}.
-+ * The method handle will accept a single argument of {@code exType},
-+ * and immediately throw it as an exception.
-+ * The method type will nominally specify a return of {@code returnType}.
-+ * The return type may be anything convenient: It doesn't matter to the
-+ * method handle's behavior, since it will never return normally.
-+ */
-+ public static
-+ MethodHandle throwException(Class<?> returnType, Class<? extends Throwable> exType) {
-+ return MethodHandleImpl.throwException(IMPL_TOKEN, MethodType.make(returnType, exType));
++ MethodHandle adapter = target;
++ MethodType adapterType = targetType;
++ int pos = -1, maxPos = targetType.parameterCount();
++ for (MethodHandle filter : filters) {
++ pos += 1;
++ if (filter == null) continue;
++ if (pos >= maxPos)
++ throw newIllegalArgumentException("too many filters");
++ MethodType filterType = filter.type();
++ if (filterType.parameterCount() != 1
++ || filterType.returnType() != targetType.parameterType(pos))
++ throw newIllegalArgumentException("target and filter types do not match");
++ adapterType = adapterType.changeParameterType(pos, filterType.parameterType(0));
++ adapter = MethodHandleImpl.filterArgument(IMPL_TOKEN, adapter, pos, filter);
++ }
++ MethodType midType = adapter.type();
++ if (midType != adapterType)
++ adapter = MethodHandleImpl.convertArguments(IMPL_TOKEN, adapter, adapterType, midType, null);
++ return adapter;
+ }
+
+ /**
@@ -1154,51 +1501,117 @@ diff --git a/src/share/classes/java/dyn/
+ * return type of the combiner.
+ * The resulting adapter is the same type as the target, except that the
+ * initial argument type of the target is dropped.
- * <p>
- * (Note that {@link #dropArguments} can be used to remove any arguments
-- * that either the {@code combiner} or {@code target} does not wish to receive.)
++ * <p>
++ * (Note that {@link #dropArguments} can be used to remove any arguments
+ * that either the {@code combiner} or {@code target} does not wish to receive.
+ * If some of the incoming arguments are destined only for the combiner,
+ * consider using {@link #collectArguments} instead, since those
+ * arguments will not need to be live on the stack on entry to the
+ * target.)
++ * <p>
++ * The first argument of the target must be identical with the
++ * return value of the combiner.
++ * <p> Here is pseudocode for the resulting adapter:
++ * <blockquote><pre>
++ * // there are N arguments in the A sequence
++ * T target(V, A[N]..., B...);
++ * V combiner(A...);
++ * T adapter(A... a, B... b) {
++ * V v = combiner(a...);
++ * return target(v, a..., b...);
++ * }
++ * </pre></blockquote>
++ * @param target the method handle to invoke after arguments are combined
++ * @param combiner method handle to call initially on the incoming arguments
++ * @return method handle which incorporates the specified argument folding logic
++ * @throws IllegalArgumentException if the first argument type of
++ * {@code target} is not the same as {@code combiner}'s return type,
++ * or if the next {@code foldArgs} argument types of {@code target}
++ * are not identical with the argument types of {@code combiner}
++ */
++ public static
++ MethodHandle foldArguments(MethodHandle target, MethodHandle combiner) {
++ MethodType targetType = target.type();
++ MethodType combinerType = combiner.type();
++ int foldArgs = combinerType.parameterCount();
++ boolean ok = (targetType.parameterCount() >= 1 + foldArgs);
++ if (!ok)
++ throw newIllegalArgumentException("target and combiner types do not match");
++ MethodType newType = targetType.dropParameterType(0);
++ return MethodHandleImpl.foldArguments(IMPL_TOKEN, target, newType, combiner);
++ }
++
++ /**
++ * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
+ * Make a method handle which adapts a target method handle,
+ * by guarding it with a test, a boolean-valued method handle.
+ * If the guard fails, a fallback handle is called instead.
+@@ -1040,65 +1351,100 @@
+
+ /**
+ * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
+- * Adapt a target method handle {@code target} by first processing
+- * its arguments, and then calling the target.
+- * The initial processing is performed by a second method handle, the {@code combiner}.
+- * After this, control passes to the {@code target}, with the same arguments.
++ * Make a method handle which adapts a target method handle,
++ * by running it inside an exception handler.
++ * If the target returns normally, the adapter returns that value.
++ * If an exception matching the specified type is thrown, the fallback
++ * handle is called instead on the exception, plus the original arguments.
* <p>
+- * The return value of the {@code combiner} is inserted into the argument list
+- * for the {@code target} at the indicated position {@code pos}, if it is non-negative.
+- * Except for this inserted argument (if any), the argument types of
+- * the target {@code target} and the {@code combiner} must be identical.
+- * <p>
+- * (Note that {@link #dropArguments} can be used to remove any arguments
+- * that either the {@code combiner} or {@code target} does not wish to receive.)
+- * <p>
- * The combiner handle must have the same argument types as the
- * target handle, but must return {@link MethodHandle} instead of
- * the ultimate return type. The returned method handle, in turn,
- * is required to have exactly the given final method type.
-+ * The first argument of the target must be identical with the
-+ * return value of the combiner.
++ * The handler must have leading parameter of {@code exType} or a supertype,
++ * followed by arguments which correspond <em>(how? TBD)</em> to
++ * all the parameters of the target.
++ * The target and handler must return the same type.
* <p> Here is pseudocode for the resulting adapter:
* <blockquote><pre>
- * signature V(A[pos]..., B...);
- * signature T(A[pos]..., V, B...);
- * T target(A... a, V v, B... b);
- * V combiner(A..., B...);
-+ * // there are N arguments in the A sequence
-+ * T target(V, A[N]..., B...);
-+ * V combiner(A...);
- * T adapter(A... a, B... b) {
+- * T adapter(A... a, B... b) {
- * V v = combiner(a..., b...);
- * return target(a..., v, b...);
-+ * V v = combiner(a...);
-+ * return target(v, a..., b...);
++ * T target(A...);
++ * T handler(ExType, A...);
++ * T adapter(A... a) {
++ * try {
++ * return target(a...);
++ * } catch (ExType ex) {
++ * return handler(ex, a...);
++ * }
* }
* </pre></blockquote>
- * @param target the method handle to invoke after arguments are combined
+- * @param target the method handle to invoke after arguments are combined
- * @param pos where the return value of {@code combiner} is to
- * be inserted as an argument to {@code target}
- * @param combiner method handle to call initially on the incoming arguments
+- * @param combiner method handle to call initially on the incoming arguments
- * @return method handle which incorporates the specified dispatch logic
- * @throws IllegalArgumentException if {@code combiner} does not itself
- * return either void or the {@code pos}-th argument of {@code target},
- * or does not have the same argument types as {@code target}
- * (minus the inserted argument)
-+ * @return method handle which incorporates the specified argument folding logic
-+ * @throws IllegalArgumentException if the first argument type of
-+ * {@code target} is not the same as {@code combiner}'s return type,
-+ * or if the next {@code foldArgs} argument types of {@code target}
-+ * are not identical with the argument types of {@code combiner}
++ * @param target method handle to call
++ * @param exType the type of exception which the handler will catch
++ * @param handler method handle to call if a matching exception is thrown
++ * @return method handle which incorporates the specified try/catch logic
++ * @throws IllegalArgumentException if {@code handler} does not accept
++ * the given exception type, or if the method handle types do
++ * not match in their return types and their
++ * corresponding parameters
*/
public static
- MethodHandle combineArguments(MethodHandle target, int pos, MethodHandle combiner) {
@@ -1218,19 +1631,73 @@ diff --git a/src/share/classes/java/dyn/
- incomingArgs = mhType.dropParameterType(pos);
- }
- if (!incomingArgs.changeReturnType(combineType).equals(combiner.type())) {
-+ MethodHandle foldArguments(MethodHandle target, MethodHandle combiner) {
-+ MethodType targetType = target.type();
-+ MethodType combinerType = combiner.type();
-+ int foldArgs = combinerType.parameterCount();
-+ boolean ok = (targetType.parameterCount() >= 1 + foldArgs);
-+ if (!ok)
- throw newIllegalArgumentException("target and combiner types do not match");
+- throw newIllegalArgumentException("target and combiner types do not match");
- }
- return MethodHandleImpl.combineArguments(IMPL_TOKEN, target, combiner, pos);
-+ MethodType newType = targetType.dropParameterType(0);
-+ return MethodHandleImpl.foldArguments(IMPL_TOKEN, target, newType, combiner);
- }
--
++ MethodHandle catchException(MethodHandle target,
++ Class<? extends Throwable> exType,
++ MethodHandle handler) {
++ MethodType targetType = target.type();
++ MethodType handlerType = handler.type();
++ boolean ok = (targetType.parameterCount() ==
++ handlerType.parameterCount() - 1);
++// for (int i = 0; ok && i < numExArgs; i++) {
++// if (targetType.parameterType(i) != handlerType.parameterType(1+i))
++// ok = false;
++// }
++ if (!ok)
++ throw newIllegalArgumentException("target and handler types do not match");
++ return MethodHandleImpl.makeGuardWithCatch(IMPL_TOKEN, target, exType, handler);
+ }
+
++ /**
++ * Produce a method handle which will throw exceptions of the given {@code exType}.
++ * The method handle will accept a single argument of {@code exType},
++ * and immediately throw it as an exception.
++ * The method type will nominally specify a return of {@code returnType}.
++ * The return type may be anything convenient: It doesn't matter to the
++ * method handle's behavior, since it will never return normally.
++ */
++ public static
++ MethodHandle throwException(Class<?> returnType, Class<? extends Throwable> exType) {
++ return MethodHandleImpl.throwException(IMPL_TOKEN, MethodType.make(returnType, exType));
++ }
++
++ /** Alias for {@link MethodType#make}, for use via static import.
++ * Example:
++ * <p><blockquote><pre>
++ * import static java.dyn.MethodHandles.*;
++ * mh = lookup().findVirtual(String.class, "hashCode", methodType(int.class));
++ * i = mh.&lt;int&gt;invoke("foo");
++ * </pre></blockquote>
++ */
++ public static MethodType methodType(Class<?> rtype) {
++ return MethodType.make(rtype);
++ }
++
++ /** Alias for {@link MethodType#make}, for use via static import.
++ * Example:
++ * <p><blockquote><pre>
++ * import static java.dyn.MethodHandles.*;
++ * mh = lookup().findVirtual(String.class, "concat", methodType(String.class, String.class));
++ * s = mh.&lt;String&gt;invoke("foo", "tball");
++ * </pre></blockquote>
++ */
++ public static MethodType methodType(Class<?> rtype, Class<?> ptype) {
++ return MethodType.make(rtype, ptype);
++ }
++
++ /** Alias for {@link MethodType#make}, for use via static import.
++ * Example:
++ * <p><blockquote><pre>
++ * import static java.dyn.MethodHandles.*;
++ * mh = lookup().findVirtual(String.class, "replace", methodType(String.class, char.class, char.class));
++ * s = mh.&lt;String&gt;invoke("blubber", 'b', 'f');
++ * </pre></blockquote>
++ */
++ public static MethodType methodType(Class<?> rtype, Class<?> ptype0, Class<?>... ptypes) {
++ return MethodType.make(rtype, ptype0, ptypes);
++ }
}
diff --git a/src/share/classes/java/dyn/MethodType.java b/src/share/classes/java/dyn/MethodType.java
--- a/src/share/classes/java/dyn/MethodType.java
@@ -1244,6 +1711,15 @@ diff --git a/src/share/classes/java/dyn/
import static sun.dyn.MemberName.newIllegalArgumentException;
/**
+@@ -63,7 +63,7 @@
+
+ static {
+ // This hack allows the implementation package special access to
+- // the internals of MethodType. In particular, the Form has all sorts
++ // the internals of MethodType. In particular, the MTImpl has all sorts
+ // of cached information useful to the implementation code.
+ MethodTypeImpl.setMethodTypeFriend(IMPL_TOKEN, new MethodTypeImpl.MethodTypeFriend() {
+ public Class<?>[] ptypes(MethodType mt) { return mt.ptypes; }
@@ -202,10 +202,11 @@
private static final MethodType[] objectOnlyTypes = new MethodType[20];
@@ -1426,7 +1902,7 @@ diff --git a/src/share/classes/sun/dyn/A
diff --git a/src/share/classes/sun/dyn/AdapterMethodHandle.java b/src/share/classes/sun/dyn/AdapterMethodHandle.java
--- a/src/share/classes/sun/dyn/AdapterMethodHandle.java
+++ b/src/share/classes/sun/dyn/AdapterMethodHandle.java
-@@ -305,17 +305,29 @@
+@@ -305,21 +305,33 @@
return (type == T_FLOAT || type == T_DOUBLE) ? 2 : 1;
}
@@ -1458,12 +1934,27 @@ diff --git a/src/share/classes/sun/dyn/A
);
}
private static long makeConv(int convOp, int argnum, int stackMove) {
-@@ -327,12 +339,12 @@
+- assert(convOp >= OP_SWAP_ARGS && convOp <= OP_SPREAD_ARGS);
++ assert(convOp >= OP_DUP_ARGS && convOp <= OP_SPREAD_ARGS);
+ byte src = 0, dest = 0;
+ if (convOp >= OP_COLLECT_ARGS && convOp <= OP_SPREAD_ARGS)
+ src = dest = T_OBJECT;
+@@ -327,12 +339,22 @@
(long) convOp << CONV_OP_SHIFT |
(int) src << CONV_SRC_TYPE_SHIFT |
(int) dest << CONV_DEST_TYPE_SHIFT |
- stackMove << CONV_STACK_MOVE_SHIFT
+ insertStackMove(stackMove)
++ );
++ }
++ private static long makeSwapConv(int convOp, int argnum, byte src, int slot2) {
++ assert(convOp >= OP_SWAP_ARGS && convOp <= OP_ROT_ARGS);
++ byte dest = src;
++ return ((long) argnum << 32 |
++ (long) convOp << CONV_OP_SHIFT |
++ (int) src << CONV_SRC_TYPE_SHIFT |
++ (int) dest << CONV_DEST_TYPE_SHIFT |
++ (int) slot2 << CONV_VMINFO_SHIFT
);
}
private static long makeConv(int convOp) {
@@ -1473,6 +1964,42 @@ diff --git a/src/share/classes/sun/dyn/A
}
private static int convCode(long conv) {
return (int)conv;
+@@ -348,16 +370,6 @@
+ /** One of OP_RETYPE_ONLY, etc. */
+ int conversionOp() { return (conversion & CONV_OP_MASK) >> CONV_OP_SHIFT; }
+
+- @Override
+- public String toString() {
+- return addTypeString(this, "Adapted[" + basicToString(nonAdapter((MethodHandle)vmtarget)) + "]");
+- }
+-
+- private static MethodHandle nonAdapter(MethodHandle mh) {
+- return (MethodHandle)
+- MethodHandleNatives.getTarget(mh, ETF_DIRECT_HANDLE);
+- }
+-
+ /* Return one plus the position of the first non-trivial difference
+ * between the given types. This is not a symmetric operation;
+ * we are considering adapting the targetType to adapterType.
+@@ -399,14 +411,14 @@
+ //if (false) return 1; // never adaptable!
+ return -1; // some significant difference
+ }
+- private static int diffParamTypes(MethodType adapterType, int tstart,
+- MethodType targetType, int astart,
++ private static int diffParamTypes(MethodType adapterType, int astart,
++ MethodType targetType, int tstart,
+ int nargs, boolean raw) {
+ assert(nargs >= 0);
+ int res = 0;
+ for (int i = 0; i < nargs; i++) {
+- Class<?> src = adapterType.parameterType(tstart+i);
+- Class<?> dest = targetType.parameterType(astart+i);
++ Class<?> src = adapterType.parameterType(astart+i);
++ Class<?> dest = targetType.parameterType(tstart+i);
+ if ((!raw
+ ? VerifyType.canPassUnchecked(src, dest)
+ : VerifyType.canPassRaw(src, dest)
@@ -437,7 +449,7 @@
if (!convOpSupported(OP_RETYPE_ONLY)) return false;
int diff = diffTypes(newType, targetType, raw);
@@ -1482,7 +2009,18 @@ diff --git a/src/share/classes/sun/dyn/A
return diff == 0;
}
-@@ -492,7 +504,7 @@
+@@ -456,7 +468,9 @@
+ static MethodHandle makeRetypeOnly(Access token,
+ MethodType newType, MethodHandle target, boolean raw) {
+ Access.check(token);
+- if (!canRetypeOnly(newType, target.type(), raw))
++ MethodType oldType = target.type();
++ if (oldType == newType) return target;
++ if (!canRetypeOnly(newType, oldType, raw))
+ return null;
+ // TO DO: clone the target guy, whatever he is, with new type.
+ return new AdapterMethodHandle(target, newType, makeConv(OP_RETYPE_ONLY));
+@@ -492,7 +506,7 @@
Access.check(token);
if (!canCheckCast(newType, target.type(), arg, castType))
return null;
@@ -1491,7 +2029,16 @@ diff --git a/src/share/classes/sun/dyn/A
return new AdapterMethodHandle(target, newType, conv, castType);
}
-@@ -643,26 +655,19 @@
+@@ -607,8 +621,6 @@
+ return null;
+ }
+
+- // TO DO: makeSwapArguments, makeRotateArguments, makeDuplicateArguments
+-
+ /** Can an adapter simply drop arguments to convert the target to newType? */
+ public static boolean canDropArguments(MethodType newType, MethodType targetType,
+ int dropArgPos, int dropArgCount) {
+@@ -643,26 +655,106 @@
Access.check(token);
if (dropArgCount == 0)
return makeRetypeOnly(IMPL_TOKEN, newType, target);
@@ -1522,15 +2069,102 @@ diff --git a/src/share/classes/sun/dyn/A
+ int dropSlot = newType.parameterSlotDepth(keep2InPos);
+ int keep1InSlot = newType.parameterSlotDepth(dropArgPos);
+ int slotCount = keep1InSlot - dropSlot;
-+ assert(dropSlot == target.type().parameterSlotDepth(dropArgPos));
+ assert(slotCount >= dropArgCount);
+ assert(target.type().parameterSlotCount() + slotCount == newType.parameterSlotCount());
+ long conv = makeConv(OP_DROP_ARGS, dropArgPos + dropArgCount - 1, -slotCount);
+ return new AdapterMethodHandle(target, newType, conv);
++ }
++
++ /** Can an adapter duplicate an argument to convert the target to newType? */
++ public static boolean canDupArguments(MethodType newType, MethodType targetType,
++ int dupArgPos, int dupArgCount) {
++ if (!convOpSupported(OP_DUP_ARGS)) return false;
++ if (diffReturnTypes(newType, targetType, false) != 0)
++ return false;
++ int nptypes = newType.parameterCount();
++ if (dupArgCount < 0 || dupArgPos + dupArgCount > nptypes)
++ return false;
++ if (targetType.parameterCount() != nptypes + dupArgCount)
++ return false;
++ // parameter types must be the same up to the duplicated arguments
++ if (diffParamTypes(newType, 0, targetType, 0, nptypes, false) != 0)
++ return false;
++ // duplicated types must be, well, duplicates
++ if (diffParamTypes(newType, dupArgPos, targetType, nptypes, dupArgCount, false) != 0)
++ return false;
++ return true;
++ }
++
++ /** Factory method: Duplicate the selected argument.
++ * Return null if this is not possible.
++ */
++ public static MethodHandle makeDupArguments(Access token,
++ MethodType newType, MethodHandle target,
++ int dupArgPos, int dupArgCount) {
++ Access.check(token);
++ if (!canDupArguments(newType, target.type(), dupArgPos, dupArgCount))
++ return null;
++ if (dupArgCount == 0)
++ return target;
++ // in arglist: [0: ...keep1 | dpos: dup... | dpos+dcount: keep2... ]
++ // out arglist: [0: ...keep1 | dpos: dup... | dpos+dcount: keep2... | dup... ]
++ int keep2InPos = dupArgPos + dupArgCount;
++ int dupSlot = newType.parameterSlotDepth(keep2InPos);
++ int keep1InSlot = newType.parameterSlotDepth(dupArgPos);
++ int slotCount = keep1InSlot - dupSlot;
++ assert(target.type().parameterSlotCount() - slotCount == newType.parameterSlotCount());
++ long conv = makeConv(OP_DUP_ARGS, dupArgPos + dupArgCount - 1, slotCount);
++ return new AdapterMethodHandle(target, newType, conv);
++ }
++
++ /** Can an adapter swap two arguments to convert the target to newType? */
++ public static boolean canSwapArguments(MethodType newType, MethodType targetType,
++ int swapArg1, int swapArg2) {
++ if (!convOpSupported(OP_SWAP_ARGS)) return false;
++ if (diffReturnTypes(newType, targetType, false) != 0)
++ return false;
++ if (swapArg1 >= swapArg2) return false; // caller resp
++ int nptypes = newType.parameterCount();
++ if (targetType.parameterCount() != nptypes)
++ return false;
++ if (swapArg1 < 0 || swapArg2 >= nptypes)
++ return false;
++ if (diffParamTypes(newType, 0, targetType, 0, swapArg1, false) != 0)
++ return false;
++ if (diffParamTypes(newType, swapArg1, targetType, swapArg2, 1, false) != 0)
++ return false;
++ if (diffParamTypes(newType, swapArg1+1, targetType, swapArg1+1, swapArg2-swapArg1-1, false) != 0)
++ return false;
++ if (diffParamTypes(newType, swapArg2, targetType, swapArg1, 1, false) != 0)
++ return false;
++ if (diffParamTypes(newType, swapArg2+1, targetType, swapArg2+1, nptypes-swapArg2-1, false) != 0)
++ return false;
++ return true;
++ }
++
++ /** Factory method: Swap the selected arguments.
++ * Return null if this is not possible.
++ */
++ public static MethodHandle makeSwapArguments(Access token,
++ MethodType newType, MethodHandle target,
++ int swapArg1, int swapArg2) {
++ Access.check(token);
++ if (swapArg1 == swapArg2)
++ return target;
++ if (swapArg1 > swapArg2) { int t = swapArg1; swapArg1 = swapArg2; swapArg2 = t; }
++ if (!canSwapArguments(newType, target.type(), swapArg1, swapArg2))
++ return null;
++ Class<?> swapType = newType.parameterType(swapArg1);
++ // in arglist: [0: ...keep1 | pos1: a1 | pos1+1: keep2... | pos2: a2 | pos2+1: keep3... ]
++ // out arglist: [0: ...keep1 | pos1: a2 | pos1+1: keep2... | pos2: a1 | pos2+1: keep3... ]
++ int swapSlot1 = newType.parameterSlotDepth(swapArg1 + 1);
++ int swapSlot2 = newType.parameterSlotDepth(swapArg2 + 1);
++ long conv = makeSwapConv(OP_SWAP_ARGS, swapArg1, basicType(swapType), swapSlot2);
++ return new AdapterMethodHandle(target, newType, conv);
}
/** Can an adapter spread an argument to convert the target to newType? */
-@@ -676,10 +681,10 @@
+@@ -676,10 +768,10 @@
if (spreadArgPos != 0 && diffParamTypes(newType, 0, targetType, 0, spreadArgPos, false) != 0)
return false;
int afterPos = spreadArgPos + spreadArgCount;
@@ -1543,7 +2177,13 @@ diff --git a/src/share/classes/sun/dyn/A
return false;
// parameter types after the spread point must also be the same
if (afterCount != 0 && diffParamTypes(newType, spreadArgPos+1, targetType, afterPos, afterCount, false) != 0)
-@@ -702,26 +707,21 @@
+@@ -697,32 +789,40 @@
+ return true;
+ }
+
++
+ /** Factory method: Spread selected argument. */
+ public static MethodHandle makeSpreadArguments(Access token,
MethodType newType, MethodHandle target,
Class<?> spreadArgType, int spreadArgPos, int spreadArgCount) {
Access.check(token);
@@ -1584,6 +2224,200 @@ diff --git a/src/share/classes/sun/dyn/A
}
// TO DO: makeCollectArguments, makeFlyby, makeRicochet
++
++ @Override
++ public String toString() {
++ return nonAdapter((MethodHandle)vmtarget).toString();
++ }
++
++ private static MethodHandle nonAdapter(MethodHandle mh) {
++ while (mh instanceof AdapterMethodHandle) {
++ mh = (MethodHandle) mh.vmtarget;
++ }
++ return mh;
++ }
+ }
+diff --git a/src/share/classes/sun/dyn/BoundMethodHandle.java b/src/share/classes/sun/dyn/BoundMethodHandle.java
+--- a/src/share/classes/sun/dyn/BoundMethodHandle.java
++++ b/src/share/classes/sun/dyn/BoundMethodHandle.java
+@@ -28,6 +28,9 @@
+ import sun.dyn.util.VerifyType;
+ import sun.dyn.util.Wrapper;
+ import java.dyn.*;
++import java.util.List;
++import sun.dyn.MethodHandleNatives.Constants;
++import static sun.dyn.MethodHandleImpl.IMPL_LOOKUP;
+
+ /**
+ * The flavor of method handle which emulates an invoke instruction
+@@ -40,7 +43,12 @@
+ private final Object argument; // argument to insert
+ private final int vmargslot; // position at which it is inserted
+
++ private static final Access IMPL_TOKEN = Access.getToken();
++ private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory(IMPL_TOKEN);
++
+ // Constructors in this class *must* be package scoped or private.
++ // Exception: JavaMethodHandle constructors are protected.
++ // (The link between JMH and BMH is temporary.)
+
+ /** Bind a direct MH to its receiver (or first ref. argument).
+ * The JVM will pre-dispatch the MH if it is not already static.
+@@ -56,32 +64,34 @@
+ } else {
+ this.vmtarget = mh;
+ }
+- }
+-
+- private static final int REF_ARG = 0, PRIM_ARG = 1, SELF_ARG = 2;
++ }
+
+ /** Insert an argument into an arbitrary method handle.
+ * If argnum is zero, inserts the first argument, etc.
+ * The argument type must be a reference.
+ */
+ BoundMethodHandle(MethodHandle mh, Object argument, int argnum) {
+- this(mh, argument, argnum, mh.type().parameterType(argnum).isPrimitive() ? PRIM_ARG : REF_ARG);
++ this(mh.type().dropParameterType(argnum),
++ mh, argument, argnum);
+ }
+
+ /** Insert an argument into an arbitrary method handle.
+ * If argnum is zero, inserts the first argument, etc.
+ */
+- BoundMethodHandle(MethodHandle mh, Object argument, int argnum, int whichArg) {
+- super(Access.TOKEN, mh.type().dropParameterType(argnum));
+- if (whichArg == PRIM_ARG)
++ BoundMethodHandle(MethodType type, MethodHandle mh, Object argument, int argnum) {
++ super(Access.TOKEN, type);
++ if (mh.type().parameterType(argnum).isPrimitive())
+ this.argument = bindPrimitiveArgument(argument, mh, argnum);
+ else {
+- if (whichArg == SELF_ARG) argument = this;
+ this.argument = checkReferenceArgument(argument, mh, argnum);
+ }
+- this.vmargslot = this.type().parameterSlotDepth(argnum);
++ this.vmargslot = type.parameterSlotDepth(argnum);
++ initTarget(mh, argnum);
++ }
++
++ private void initTarget(MethodHandle mh, int argnum) {
+ if (MethodHandleNatives.JVM_SUPPORT) {
+- this.vmtarget = null; // maybe updated by JVM
++ this.vmtarget = null; // maybe updated by JVM
+ MethodHandleNatives.init(this, mh, argnum);
+ } else {
+ this.vmtarget = mh;
+@@ -97,29 +107,65 @@
+ assert(this.getClass() == AdapterMethodHandle.class);
+ }
+
+- /** Initialize the current object as a method handle, binding it
+- * as the {@code argnum}th argument of the method handle {@code entryPoint}.
+- * The invocation type of the resulting method handle will be the
+- * same as {@code entryPoint}, except that the {@code argnum}th argument
+- * type will be dropped.
+- */
+- public BoundMethodHandle(MethodHandle entryPoint, int argnum) {
+- this(entryPoint, null, argnum, SELF_ARG);
+-
+- // Note: If the conversion fails, perhaps because of a bad entryPoint,
+- // the MethodHandle.type field will not be filled in, and therefore
+- // no MH.invoke call will ever succeed. The caller may retain a pointer
+- // to the broken method handle, but no harm can be done with it.
+- }
+-
+- /** Initialize the current object as a method handle, binding it
++ /** Initialize the current object as a Java method handle, binding it
+ * as the first argument of the method handle {@code entryPoint}.
+ * The invocation type of the resulting method handle will be the
+ * same as {@code entryPoint}, except that the first argument
+ * type will be dropped.
+ */
+- public BoundMethodHandle(MethodHandle entryPoint) {
+- this(entryPoint, null, 0, SELF_ARG);
++ protected BoundMethodHandle(MethodHandle entryPoint) {
++ super(Access.TOKEN, entryPoint.type().dropParameterType(0));
++ this.argument = this; // kludge; get rid of
++ this.vmargslot = this.type().parameterSlotDepth(0);
++ initTarget(entryPoint, 0);
++ assert(this instanceof JavaMethodHandle);
++ }
++
++ /** Initialize the current object as a Java method handle.
++ */
++ protected BoundMethodHandle(String entryPointName, MethodType type, boolean matchArity) {
++ super(Access.TOKEN, null);
++ MethodHandle entryPoint
++ = findJavaMethodHandleEntryPoint(this.getClass(),
++ entryPointName, type, matchArity);
++ MethodHandleImpl.initType(this, entryPoint.type().dropParameterType(0));
++ this.argument = this; // kludge; get rid of
++ this.vmargslot = this.type().parameterSlotDepth(0);
++ initTarget(entryPoint, 0);
++ assert(this instanceof JavaMethodHandle);
++ }
++
++ private static
++ MethodHandle findJavaMethodHandleEntryPoint(Class<?> caller,
++ String name,
++ MethodType type,
++ boolean matchArity) {
++ if (matchArity) type.getClass(); // elicit NPE
++ List<MemberName> methods = IMPL_NAMES.getMethods(caller, true, name, null, caller);
++ MethodType foundType = null;
++ MemberName foundMethod = null;
++ for (MemberName method : methods) {
++ MethodType mtype = method.getMethodType();
++ if (type != null && type.parameterCount() != mtype.parameterCount())
++ continue;
++ else if (foundType == null)
++ foundType = mtype;
++ else if (foundType != mtype)
++ throw new IllegalArgumentException("more than one method named "+name+" in "+caller.getName());
++ // discard overrides
++ if (foundMethod == null)
++ foundMethod = method;
++ else if (foundMethod.getDeclaringClass().isAssignableFrom(method.getDeclaringClass()))
++ foundMethod = method;
++ }
++ if (foundMethod == null)
++ throw new IllegalArgumentException("no method named "+name+" in "+caller.getName());
++ MethodHandle entryPoint = MethodHandleImpl.findMethod(IMPL_TOKEN, foundMethod, true, caller);
++ if (type != null) {
++ MethodType epType = type.insertParameterType(0, entryPoint.type().parameterType(0));
++ entryPoint = MethodHandles.convertArguments(entryPoint, epType);
++ }
++ return entryPoint;
+ }
+
+ /** Make sure the given {@code argument} can be used as {@code argnum}-th
+@@ -175,6 +221,24 @@
+
+ @Override
+ public String toString() {
+- return "Bound[" + super.toString() + "]";
++ MethodHandle mh = this;
++ while (mh instanceof BoundMethodHandle) {
++ Object info = MethodHandleNatives.getTargetInfo(mh);
++ if (info instanceof MethodHandle) {
++ mh = (MethodHandle) info;
++ } else {
++ String name = null;
++ if (info instanceof MemberName)
++ name = ((MemberName)info).getName();
++ if (name != null)
++ return name;
++ else
++ return super.toString(); // <unknown>, probably
++ }
++ assert(mh != this);
++ if (mh instanceof JavaMethodHandle)
++ break; // access JMH.toString(), not BMH.toString()
++ }
++ return mh.toString();
+ }
+ }
diff --git a/src/share/classes/sun/dyn/CallSiteImpl.java b/src/share/classes/sun/dyn/CallSiteImpl.java
--- a/src/share/classes/sun/dyn/CallSiteImpl.java
+++ b/src/share/classes/sun/dyn/CallSiteImpl.java
@@ -2012,7 +2846,7 @@ diff --git a/src/share/classes/sun/dyn/F
throw new UnsupportedOperationException("NYI");
}
-@@ -242,8 +231,8 @@
+@@ -242,8 +231,13 @@
* generated once per type erasure family, and reused across adapters.
*/
static abstract class Adapter extends JavaMethodHandle {
@@ -2020,10 +2854,15 @@ diff --git a/src/share/classes/sun/dyn/F
- protected final MethodHandle target;
+ protected final MethodHandle filter; // transforms one or more arguments
+ protected final MethodHandle target; // ultimate target
++
++ @Override
++ public String toString() {
++ return target.toString();
++ }
protected boolean isPrototype() { return target == null; }
protected Adapter(MethodHandle entryPoint) {
-@@ -287,52 +276,4221 @@
+@@ -287,52 +281,4221 @@
}
}
@@ -6300,18 +7139,25 @@ diff --git a/src/share/classes/sun/dyn/F
import java.dyn.MethodType;
/**
-@@ -42,16 +41,16 @@
+@@ -42,16 +41,21 @@
protected final MethodHandle filter; // Object -> Object
protected final MethodHandle target; // Object -> Object
- protected Object entryPoint(Object argument) {
-+ protected Object invoke(Object argument) throws Throwable {
- Object filteredArgument = filter.<Object>invoke(argument);
- return target.<Object>invoke(filteredArgument);
+- Object filteredArgument = filter.<Object>invoke(argument);
+- return target.<Object>invoke(filteredArgument);
++ @Override
++ public String toString() {
++ return target.toString();
}
- private static final MethodHandle entryPoint =
- MethodHandleImpl.IMPL_LOOKUP.findVirtual(FilterOneArgument.class, "entryPoint", MethodType.makeGeneric(1));
++ protected Object invoke(Object argument) throws Throwable {
++ Object filteredArgument = filter.invoke(argument);
++ return target.invoke(filteredArgument);
++ }
++
+ private static final MethodHandle INVOKE =
+ MethodHandleImpl.IMPL_LOOKUP.findVirtual(FilterOneArgument.class, "invoke", MethodType.makeGeneric(1));
@@ -6321,6 +7167,17 @@ diff --git a/src/share/classes/sun/dyn/F
this.filter = filter;
this.target = target;
}
+@@ -62,10 +66,6 @@
+ return new FilterOneArgument(filter, target);
+ }
+
+- public String toString() {
+- return filter + "|>" + target;
+- }
+-
+ // MethodHandle make(MethodHandle filter1, MethodHandle filter2, MethodHandle target) {
+ // MethodHandle filter = make(filter1, filter2);
+ // return make(filter, target);
diff --git a/src/share/classes/sun/dyn/FromGeneric.java b/src/share/classes/sun/dyn/FromGeneric.java
--- a/src/share/classes/sun/dyn/FromGeneric.java
+++ b/src/share/classes/sun/dyn/FromGeneric.java
@@ -6357,7 +7214,19 @@ diff --git a/src/share/classes/sun/dyn/F
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
}
-@@ -284,11 +284,11 @@
+@@ -260,6 +260,11 @@
+ protected final MethodHandle convert; // raw(R) => Object
+ protected final MethodHandle target; // (any**N) => R
+
++ @Override
++ public String toString() {
++ return target.toString();
++ }
++
+ protected boolean isPrototype() { return target == null; }
+ protected Adapter(MethodHandle entryPoint) {
+ this(entryPoint, null, entryPoint, null);
+@@ -284,11 +289,11 @@
// { return new ThisType(entryPoint, convert, target); }
/// Conversions on the value returned from the target.
@@ -6374,7 +7243,7 @@ diff --git a/src/share/classes/sun/dyn/F
static private final String CLASS_PREFIX; // "sun.dyn.FromGeneric$"
static {
-@@ -317,11 +317,11 @@
+@@ -317,11 +322,11 @@
{ super(e, i, c, t); }
protected xA2 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
{ return new xA2(e, i, c, t); }
@@ -6391,7 +7260,7 @@ diff --git a/src/share/classes/sun/dyn/F
}
// */
-@@ -342,7 +342,7 @@
+@@ -342,7 +347,7 @@
" protected @cat@ makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)",
" { return new @cat@(e, i, c, t); }",
" //@each-R@",
@@ -6400,7 +7269,7 @@ diff --git a/src/share/classes/sun/dyn/F
" //@end-R@",
" }",
} };
-@@ -498,11 +498,11 @@
+@@ -498,11 +503,11 @@
{ super(e, i, c, t); }
protected A0 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
{ return new A0(e, i, c, t); }
@@ -6417,7 +7286,7 @@ diff --git a/src/share/classes/sun/dyn/F
}
static class A1 extends Adapter {
protected A1(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
-@@ -510,11 +510,11 @@
+@@ -510,11 +515,11 @@
{ super(e, i, c, t); }
protected A1 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
{ return new A1(e, i, c, t); }
@@ -6434,7 +7303,7 @@ diff --git a/src/share/classes/sun/dyn/F
}
static class A2 extends Adapter {
protected A2(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
-@@ -522,11 +522,11 @@
+@@ -522,11 +527,11 @@
{ super(e, i, c, t); }
protected A2 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
{ return new A2(e, i, c, t); }
@@ -6451,7 +7320,7 @@ diff --git a/src/share/classes/sun/dyn/F
}
static class A3 extends Adapter {
protected A3(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
-@@ -534,11 +534,11 @@
+@@ -534,11 +539,11 @@
{ super(e, i, c, t); }
protected A3 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
{ return new A3(e, i, c, t); }
@@ -6468,7 +7337,7 @@ diff --git a/src/share/classes/sun/dyn/F
}
static class A4 extends Adapter {
protected A4(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
-@@ -546,11 +546,11 @@
+@@ -546,11 +551,11 @@
{ super(e, i, c, t); }
protected A4 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
{ return new A4(e, i, c, t); }
@@ -6485,7 +7354,7 @@ diff --git a/src/share/classes/sun/dyn/F
}
static class A5 extends Adapter {
protected A5(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
-@@ -558,11 +558,11 @@
+@@ -558,11 +563,11 @@
{ super(e, i, c, t); }
protected A5 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
{ return new A5(e, i, c, t); }
@@ -6502,7 +7371,7 @@ diff --git a/src/share/classes/sun/dyn/F
}
static class A6 extends Adapter {
protected A6(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
-@@ -570,11 +570,11 @@
+@@ -570,11 +575,11 @@
{ super(e, i, c, t); }
protected A6 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
{ return new A6(e, i, c, t); }
@@ -6519,7 +7388,7 @@ diff --git a/src/share/classes/sun/dyn/F
}
static class A7 extends Adapter {
protected A7(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
-@@ -582,11 +582,11 @@
+@@ -582,11 +587,11 @@
{ super(e, i, c, t); }
protected A7 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
{ return new A7(e, i, c, t); }
@@ -6536,7 +7405,7 @@ diff --git a/src/share/classes/sun/dyn/F
}
static class A8 extends Adapter {
protected A8(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
-@@ -594,11 +594,11 @@
+@@ -594,11 +599,11 @@
{ super(e, i, c, t); }
protected A8 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
{ return new A8(e, i, c, t); }
@@ -6553,7 +7422,7 @@ diff --git a/src/share/classes/sun/dyn/F
}
static class A9 extends Adapter {
protected A9(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
-@@ -606,11 +606,11 @@
+@@ -606,11 +611,11 @@
{ super(e, i, c, t); }
protected A9 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
{ return new A9(e, i, c, t); }
@@ -6570,7 +7439,7 @@ diff --git a/src/share/classes/sun/dyn/F
}
static class A10 extends Adapter {
protected A10(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
-@@ -618,10 +618,10 @@
+@@ -618,10 +623,10 @@
{ super(e, i, c, t); }
protected A10 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
{ return new A10(e, i, c, t); }
@@ -6589,24 +7458,37 @@ diff --git a/src/share/classes/sun/dyn/I
diff --git a/src/share/classes/sun/dyn/Invokers.java b/src/share/classes/sun/dyn/Invokers.java
--- a/src/share/classes/sun/dyn/Invokers.java
+++ b/src/share/classes/sun/dyn/Invokers.java
-@@ -44,6 +44,9 @@
+@@ -44,12 +44,16 @@
// generic (untyped) invoker for the outgoing call
private /*lazy*/ MethodHandle genericInvoker;
+ // generic (untyped) invoker for the outgoing call; accepts a single Object[]
-+ private /*lazy*/ MethodHandle varargsInvoker;
++ private final /*lazy*/ MethodHandle[] varargsInvokers;
+
/** Compute and cache information common to all collecting adapters
* that implement members of the erasure-family of the given erased type.
*/
-@@ -77,7 +80,9 @@
- }
-
- public MethodHandle varargsInvoker() {
+ public Invokers(Access token, MethodType targetType) {
+ Access.check(token);
+ this.targetType = targetType;
++ this.varargsInvokers = new MethodHandle[targetType.parameterCount()+1];
+ }
+
+ public static MethodType invokerType(MethodType targetType) {
+@@ -76,8 +80,14 @@
+ return invoker;
+ }
+
+- public MethodHandle varargsInvoker() {
- throw new UnsupportedOperationException("NYI");
-+ MethodHandle invoker = genericInvoker();
-+ MethodType vaType = MethodType.make(Object.class, Object[].class);
-+ return MethodHandles.spreadArguments(invoker, invokerType(vaType));
++ public MethodHandle varargsInvoker(int objectArgCount) {
++ MethodHandle vaInvoker = varargsInvokers[objectArgCount];
++ if (vaInvoker != null) return vaInvoker;
++ MethodHandle gInvoker = genericInvoker();
++ MethodType vaType = MethodType.makeGeneric(objectArgCount, true);
++ vaInvoker = MethodHandles.spreadArguments(gInvoker, invokerType(vaType));
++ varargsInvokers[objectArgCount] = vaInvoker;
++ return vaInvoker;
}
public String toString() {
@@ -6622,7 +7504,15 @@ diff --git a/src/share/classes/sun/dyn/M
import java.dyn.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
-@@ -93,7 +93,7 @@
+@@ -33,6 +33,7 @@
+ import java.lang.reflect.Member;
+ import java.lang.reflect.Modifier;
+ import java.util.ArrayList;
++import java.util.Arrays;
+ import java.util.Collections;
+ import java.util.Iterator;
+ import java.util.List;
+@@ -93,7 +94,7 @@
}
if (type instanceof String) {
String sig = (String) type;
@@ -6631,7 +7521,7 @@ diff --git a/src/share/classes/sun/dyn/M
this.type = res;
return res;
}
-@@ -135,7 +135,7 @@
+@@ -135,7 +136,7 @@
}
if (type instanceof String) {
String sig = (String) type;
@@ -6640,7 +7530,7 @@ diff --git a/src/share/classes/sun/dyn/M
Class<?> res = mtype.returnType();
this.type = res;
return res;
-@@ -155,9 +155,9 @@
+@@ -155,9 +156,9 @@
if (type instanceof String)
return (String) type;
if (isInvocable())
@@ -6652,7 +7542,7 @@ diff --git a/src/share/classes/sun/dyn/M
}
public int getModifiers() {
-@@ -353,6 +353,8 @@
+@@ -353,6 +354,8 @@
return type.toString(); // class java.lang.String
// else it is a field, method, or constructor
StringBuilder buf = new StringBuilder();
@@ -6661,7 +7551,16 @@ diff --git a/src/share/classes/sun/dyn/M
if (getDeclaringClass() != null) {
buf.append(getName(clazz));
buf.append('.');
-@@ -408,6 +410,9 @@
+@@ -381,7 +384,7 @@
+ private static String getName(Object obj) {
+ if (obj instanceof Class<?>)
+ return ((Class<?>)obj).getName();
+- return obj.toString();
++ return String.valueOf(obj);
+ }
+
+ // Queries to the JVM:
+@@ -408,6 +411,9 @@
public static NoAccessException newNoAccessException(MemberName name, Class<?> lookupClass) {
return newNoAccessException("cannot access", name, lookupClass);
}
@@ -6671,7 +7570,7 @@ diff --git a/src/share/classes/sun/dyn/M
public static NoAccessException newNoAccessException(String message,
MemberName name, Class<?> lookupClass) {
message += ": " + name;
-@@ -436,7 +441,7 @@
+@@ -436,7 +442,7 @@
matchFlags &= ALLOWED_FLAGS;
String matchSig = null;
if (matchType != null) {
@@ -6680,8 +7579,22 @@ diff --git a/src/share/classes/sun/dyn/M
if (matchSig.startsWith("("))
matchFlags &= ~(ALL_KINDS & ~IS_INVOCABLE);
else
-@@ -457,7 +462,7 @@
- totalCount += bufCount;
+@@ -447,17 +453,18 @@
+ MemberName[] buf = newMemberBuffer(len1);
+ int totalCount = 0;
+ ArrayList<MemberName[]> bufs = null;
++ int bufCount = 0;
+ for (;;) {
+- int bufCount = MethodHandleNatives.getMembers(defc,
++ bufCount = MethodHandleNatives.getMembers(defc,
+ matchName, matchSig, matchFlags,
+ lookupClass,
+ totalCount, buf);
+ if (bufCount <= buf.length) {
+- if (bufCount >= 0)
+- totalCount += bufCount;
++ if (bufCount < 0) bufCount = 0;
++ totalCount += bufCount;
break;
}
- // JVM returned tp us with an intentional overflow!
@@ -6689,10 +7602,19 @@ diff --git a/src/share/classes/sun/dyn/M
totalCount += buf.length;
int excess = bufCount - buf.length;
if (bufs == null) bufs = new ArrayList<MemberName[]>(1);
+@@ -473,7 +480,7 @@
+ Collections.addAll(result, buf0);
+ }
+ }
+- Collections.addAll(result, buf);
++ result.addAll(Arrays.asList(buf).subList(0, bufCount));
+ // Signature matching is not the same as type matching, since
+ // one signature might correspond to several types.
+ // So if matchType is a Class or MethodType, refilter the results.
diff --git a/src/share/classes/sun/dyn/MethodHandleImpl.java b/src/share/classes/sun/dyn/MethodHandleImpl.java
--- a/src/share/classes/sun/dyn/MethodHandleImpl.java
+++ b/src/share/classes/sun/dyn/MethodHandleImpl.java
-@@ -25,12 +25,16 @@
+@@ -25,12 +25,19 @@
package sun.dyn;
@@ -6704,12 +7626,41 @@ diff --git a/src/share/classes/sun/dyn/M
import sun.dyn.util.VerifyType;
import java.dyn.NoAccessException;
+import java.util.ArrayList;
++import java.util.Collections;
++import java.util.Iterator;
++import java.util.List;
+import sun.dyn.empty.Empty;
+import sun.dyn.util.ValueConversions;
import static sun.dyn.MemberName.newIllegalArgumentException;
import static sun.dyn.MemberName.newNoAccessException;
-@@ -106,8 +110,8 @@
+@@ -57,6 +64,25 @@
+ static final int INT_FIELD = 0;
+ static final long LONG_FIELD = 0;
+
++ /** Access methods for the internals of MethodHandle, supplied to
++ * MethodHandleImpl as a trusted agent.
++ */
++ static public interface MethodHandleFriend {
++ void initType(MethodHandle mh, MethodType type);
++ }
++ public static void setMethodHandleFriend(Access token, MethodHandleFriend am) {
++ Access.check(token);
++ if (METHOD_HANDLE_FRIEND != null)
++ throw new InternalError(); // just once
++ METHOD_HANDLE_FRIEND = am;
++ }
++ static private MethodHandleFriend METHOD_HANDLE_FRIEND;
++
++ // NOT public
++ static void initType(MethodHandle mh, MethodType type) {
++ METHOD_HANDLE_FRIEND.initType(mh, type);
++ }
++
+ // type is defined in java.dyn.MethodHandle, which is platform-independent
+
+ // vmentry (a void* field) is used *only* by by the JVM.
+@@ -106,8 +132,8 @@
}
static {
@@ -6720,7 +7671,7 @@ diff --git a/src/share/classes/sun/dyn/M
if (IMPL_LOOKUP_INIT == null)
throw new InternalError();
}
-@@ -203,8 +207,11 @@
+@@ -203,8 +229,11 @@
if (info instanceof DirectMethodHandle) {
DirectMethodHandle dmh = (DirectMethodHandle) info;
if (receiver == null ||
@@ -6734,7 +7685,7 @@ diff --git a/src/share/classes/sun/dyn/M
}
}
if (target instanceof DirectMethodHandle)
-@@ -223,7 +230,7 @@
+@@ -223,7 +252,7 @@
MethodHandle bindArgument(Access token,
MethodHandle target, int argnum, Object receiver) {
Access.check(token);
@@ -6743,7 +7694,95 @@ diff --git a/src/share/classes/sun/dyn/M
}
public static MethodHandle convertArguments(Access token,
-@@ -274,80 +281,302 @@
+@@ -232,6 +261,87 @@
+ MethodType oldType,
+ int[] permutationOrNull) {
+ Access.check(token);
++ if (permutationOrNull != null) {
++ int outargs = oldType.parameterCount(), inargs = newType.parameterCount();
++ if (permutationOrNull.length != outargs)
++ throw newIllegalArgumentException("wrong number of arguments in permutation");
++ // Make the individual outgoing argument types match up first.
++ Class<?>[] callTypeArgs = new Class<?>[outargs];
++ for (int i = 0; i < outargs; i++)
++ callTypeArgs[i] = newType.parameterType(permutationOrNull[i]);
++ MethodType callType = MethodType.make(oldType.returnType(), callTypeArgs);
++ target = convertArguments(token, target, callType, oldType, null);
++ assert(target != null);
++ oldType = target.type();
++ List<Integer> goal = new ArrayList<Integer>();
++ List<Integer> state = new ArrayList<Integer>();
++ List<Integer> drops = new ArrayList<Integer>();
++ List<Integer> dups = new ArrayList<Integer>();
++ final int TOKEN = 10; // to mark items which are symbolic only
++ // state represents the argument values coming into target
++ for (int i = 0; i < outargs; i++) {
++ state.add(permutationOrNull[i] * TOKEN);
++ }
++ // goal represents the desired state
++ for (int i = 0; i < inargs; i++) {
++ if (state.contains(i * TOKEN)) {
++ goal.add(i * TOKEN);
++ } else {
++ // adapter must initially drop all unused arguments
++ drops.add(i);
++ }
++ }
++ // detect duplications
++ while (state.size() > goal.size()) {
++ for (int i2 = 0; i2 < state.size(); i2++) {
++ int arg1 = state.get(i2);
++ int i1 = state.indexOf(arg1);
++ if (i1 != i2) {
++ // found duplicate occurrence at i2
++ int arg2 = (inargs++) * TOKEN;
++ state.set(i2, arg2);
++ dups.add(goal.indexOf(arg1));
++ goal.add(arg2);
++ }
++ }
++ }
++ assert(state.size() == goal.size());
++ int size = goal.size();
++ while (!state.equals(goal)) {
++ // Swap like the wind!
++ // FIXME: Use a rotation when possible.
++ for (int i = 0; i < size; i++) {
++ int arg = state.get(i);
++ if (arg != goal.get(i)) {
++ int j = goal.indexOf(arg);
++ target = AdapterMethodHandle.makeSwapArguments(token, target.type(), target, i, j);
++ if (target == null) throw newIllegalArgumentException("cannot swap");
++ oldType = target.type();
++ Collections.swap(state, i, j);
++ }
++ }
++ }
++ Collections.reverse(dups);
++ for (int i : dups) {
++ MethodType dupType = oldType.dropParameterType(i);
++ int dupArgPos = i, dupArgCount = 1; // FIXME: Batch up the dups.
++ target = AdapterMethodHandle.makeDupArguments(token, dupType, target, dupArgPos, dupArgCount);
++ if (target == null) throw newIllegalArgumentException("cannot dup");
++ oldType = target.type();
++ }
++ //Collections.reverse(drops);
++ for (int i : drops) {
++ MethodType dropType = oldType.insertParameterType(i, newType.parameterType(i));
++ int dropArgPos = i, dropArgCount = 1; // FIXME: Batch up drops.
++ target = AdapterMethodHandle.makeDropArguments(token, dropType, target, dropArgPos, dropArgCount);
++ if (target == null) throw newIllegalArgumentException("cannot drop");
++ oldType = target.type();
++ }
++ }
++ if (newType == oldType)
++ return target;
++ if (oldType.parameterCount() != newType.parameterCount())
++ throw new IllegalArgumentException("mismatched parameter count");
+ MethodHandle res = AdapterMethodHandle.makePairwiseConvert(token, newType, target);
+ if (res != null)
+ return res;
+@@ -274,81 +384,343 @@
ptypes[spreadArg + i] = VerifyType.spreadArgElementType(spreadType, i);
MethodType midType = MethodType.make(newType.returnType(), ptypes);
// after spreading, some arguments may need further conversion
@@ -6758,7 +7797,7 @@ diff --git a/src/share/classes/sun/dyn/M
+ return res;
+ res = SpreadGeneric.make(target2, spreadCount);
+ if (res != null)
-+ return convertArguments(token, res, newType, res.type(), null);
++ res = convertArguments(token, res, newType, res.type(), null);
return res;
}
@@ -6782,11 +7821,36 @@ diff --git a/src/share/classes/sun/dyn/M
+ assert(newType.parameterCount() == collectArg + colType.parameterCount());
+ assert(oldType.parameterCount() == collectArg + 1);
+ MethodHandle gtarget = convertArguments(token, target, oldType.generic(), oldType, null);
-+ MethodHandle gcollector = convertArguments(token, collector, colType.generic(), oldType, null);
++ MethodHandle gcollector = convertArguments(token, collector, colType.generic(), colType, null);
++ if (gtarget == null || gcollector == null) return null;
+ MethodHandle gresult = FilterGeneric.makeArgumentCollector(gcollector, gtarget);
+ MethodHandle result = convertArguments(token, gresult, newType, gresult.type(), null);
+ return result;
}
++
++ public static MethodHandle filterArgument(Access token,
++ MethodHandle target,
++ int pos,
++ MethodHandle filter) {
++ Access.check(token);
++ MethodType ttype = target.type(), gttype = ttype.generic();
++ if (ttype != gttype) {
++ target = convertArguments(token, target, gttype, ttype, null);
++ ttype = gttype;
++ }
++ MethodType ftype = filter.type(), gftype = ftype.generic();
++ if (ftype.parameterCount() != 1)
++ throw new InternalError();
++ if (ftype != gftype) {
++ filter = convertArguments(token, filter, gftype, ftype, null);
++ ftype = gftype;
++ }
++ if (ftype == ttype) {
++ // simple unary case
++ return FilterOneArgument.make(filter, target);
++ }
++ return FilterGeneric.makeArgumentFilter(pos, filter, target);
++ }
+
+ public static MethodHandle foldArguments(Access token,
+ MethodHandle target,
@@ -6796,7 +7860,8 @@ diff --git a/src/share/classes/sun/dyn/M
+ MethodType oldType = target.type();
+ MethodType ctype = combiner.type();
+ MethodHandle gtarget = convertArguments(token, target, oldType.generic(), oldType, null);
-+ MethodHandle gcombiner = convertArguments(token, combiner, ctype.generic(), oldType, null);
++ MethodHandle gcombiner = convertArguments(token, combiner, ctype.generic(), ctype, null);
++ if (gtarget == null || gcombiner == null) return null;
+ MethodHandle gresult = FilterGeneric.makeArgumentFolder(gcombiner, gtarget);
+ MethodHandle result = convertArguments(token, gresult, newType, gresult.type(), null);
+ return result;
@@ -6806,14 +7871,13 @@ diff --git a/src/share/classes/sun/dyn/M
MethodHandle dropArguments(Access token, MethodHandle target,
MethodType newType, int argnum) {
Access.check(token);
-- throw new UnsupportedOperationException("NYI");
+ int drops = newType.parameterCount() - target.type().parameterCount();
-+ MethodHandle res = AdapterMethodHandle.makeDropArguments(token, newType, target, argnum, drops);
-+ if (res != null)
-+ return res;
-+ throw new UnsupportedOperationException("NYI");
-+ }
-+
++ MethodHandle res = AdapterMethodHandle.makeDropArguments(token, newType, target, argnum, drops);
++ if (res != null)
++ return res;
+ throw new UnsupportedOperationException("NYI");
+ }
+
+ private static class GuardWithTest extends JavaMethodHandle {
+ private final MethodHandle test, target, fallback;
+ public GuardWithTest(MethodHandle test, MethodHandle target, MethodHandle fallback) {
@@ -6821,6 +7885,10 @@ diff --git a/src/share/classes/sun/dyn/M
+ this.test = test;
+ this.target = target;
+ this.fallback = fallback;
++ }
++ @Override
++ public String toString() {
++ return target.toString();
+ }
+ private Object invoke_L0() throws Throwable {
+ if (test.<boolean>invoke())
@@ -6885,8 +7953,8 @@ diff --git a/src/share/classes/sun/dyn/M
+ return invokes.toArray(new MethodHandle[0]);
+ };
+ static final MethodHandle[] INVOKES = makeInvokes();
- }
-
++ }
++
public static
MethodHandle makeGuardWithTest(Access token,
- final MethodHandle test,
@@ -6914,6 +7982,7 @@ diff --git a/src/share/classes/sun/dyn/M
+ MethodHandle gtest = convertArguments(token, test, gtype.changeReturnType(boolean.class), test.type(), null);
+ MethodHandle gtarget = convertArguments(token, target, gtype, type, null);
+ MethodHandle gfallback = convertArguments(token, fallback, gtype, type, null);
++ if (gtest == null || gtarget == null || gfallback == null) return null;
+ MethodHandle gguard = new GuardWithTest(gtest, gtarget, gfallback);
+ return convertArguments(token, gguard, type, gtype, null);
+ } else {
@@ -6922,6 +7991,7 @@ diff --git a/src/share/classes/sun/dyn/M
+ MethodHandle gtarget = spreadArguments(token, target, gtype, 0);
+ MethodHandle gfallback = spreadArguments(token, fallback, gtype, 0);
+ MethodHandle gguard = new GuardWithTest(gtest, gtarget, gfallback);
++ if (gtest == null || gtarget == null || gfallback == null) return null;
+ return collectArguments(token, gguard, type, 0, null);
}
- if (rtype.isPrimitive()) {
@@ -6957,6 +8027,10 @@ diff --git a/src/share/classes/sun/dyn/M
- MethodType invokeType = MethodType.makeGeneric(0, true);
- MethodHandle vh = IMPL_LOOKUP.bind(this, "invoke", invokeType);
- return MethodHandles.collectArguments(vh, target.type());
++ @Override
++ public String toString() {
++ return target.toString();
++ }
+ private Object invoke_L0() throws Throwable {
+ try {
+ return target.<Object>invoke();
@@ -7058,20 +8132,23 @@ diff --git a/src/share/classes/sun/dyn/M
+ MethodHandle catcher) {
+ Access.check(token);
+ MethodType type = target.type();
++ MethodType ctype = catcher.type();
+ int nargs = type.parameterCount();
+ if (nargs < GuardWithCatch.INVOKES.length) {
+ MethodType gtype = type.generic();
-+ MethodType catchType = gtype.insertParameterType(0, Throwable.class);
++ MethodType gcatchType = gtype.insertParameterType(0, Throwable.class);
+ MethodHandle gtarget = convertArguments(token, target, gtype, type, null);
-+ MethodHandle gcatcher = convertArguments(token, catcher, catchType, type, null);
++ MethodHandle gcatcher = convertArguments(token, catcher, gcatchType, ctype, null);
+ MethodHandle gguard = new GuardWithCatch(gtarget, exType, gcatcher);
++ if (gtarget == null || gcatcher == null || gguard == null) return null;
+ return convertArguments(token, gguard, type, gtype, null);
+ } else {
+ MethodType gtype = MethodType.makeGeneric(1);
-+ MethodType catchType = gtype.insertParameterType(0, Throwable.class);
++ MethodType gcatchType = gtype.insertParameterType(0, Throwable.class);
+ MethodHandle gtarget = spreadArguments(token, target, gtype, 0);
-+ MethodHandle gcatcher = spreadArguments(token, catcher, catchType, 1);
++ MethodHandle gcatcher = spreadArguments(token, catcher, gcatchType, 1);
+ MethodHandle gguard = new GuardWithCatch(gtarget, exType, gcatcher);
++ if (gtarget == null || gcatcher == null || gguard == null) return null;
+ return collectArguments(token, gguard, type, 0, null);
+ }
}
@@ -7084,18 +8161,53 @@ diff --git a/src/share/classes/sun/dyn/M
+ return AdapterMethodHandle.makeRetypeOnly(token, type, THROW_EXCEPTION, true);
}
+- protected static String basicToString(MethodHandle target) {
+ static final MethodHandle THROW_EXCEPTION
+ = IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "throwException",
+ MethodType.make(Empty.class, Throwable.class));
+ static <T extends Throwable> Empty throwException(T t) throws T { throw t; }
+
- protected static String basicToString(MethodHandle target) {
++ public static String getNameString(Access token, MethodHandle target) {
++ Access.check(token);
MemberName name = null;
if (target != null)
+ name = MethodHandleNatives.getMethodName(target);
+@@ -357,17 +729,13 @@
+ return name.getName();
+ }
+
+- protected static String addTypeString(MethodHandle target, String name) {
+- if (target == null) return name;
+- return name+target.type();
++ public static String addTypeString(MethodHandle target) {
++ if (target == null) return "null";
++ return target.toString() + target.type();
+ }
++
+ static RuntimeException newIllegalArgumentException(String string) {
+ return new IllegalArgumentException(string);
+ }
+
+- @Override
+- public String toString() {
+- MethodHandle self = (MethodHandle) this;
+- return addTypeString(self, basicToString(self));
+- }
+ }
diff --git a/src/share/classes/sun/dyn/MethodHandleNatives.java b/src/share/classes/sun/dyn/MethodHandleNatives.java
--- a/src/share/classes/sun/dyn/MethodHandleNatives.java
+++ b/src/share/classes/sun/dyn/MethodHandleNatives.java
-@@ -123,7 +123,7 @@
+@@ -84,8 +84,7 @@
+ }
+
+ /** Fetch the target of this method handle.
+- * If it directly targets a method, return a tuple of method info.
+- * The info is of the form new Object[]{defclass, name, sig, refclass}.
++ * If it directly targets a method, return a MemberName for the method.
+ * If it is chained to another method handle, return that handle.
+ */
+ static Object getTargetInfo(MethodHandle self) {
+@@ -123,7 +122,7 @@
registerNatives();
JVM_SUPPORT_ = true;
JVM_PUSH_LIMIT_ = getConstant(Constants.GC_JVM_PUSH_LIMIT);
@@ -7104,7 +8216,7 @@ diff --git a/src/share/classes/sun/dyn/M
//sun.reflect.Reflection.registerMethodsToFilter(MethodHandleImpl.class, "init");
} catch (UnsatisfiedLinkError ee) {
// ignore; if we use init() methods later we'll see linkage errors
-@@ -149,7 +149,7 @@
+@@ -149,7 +148,7 @@
// MethodHandleImpl
static final int // for getConstant
GC_JVM_PUSH_LIMIT = 0,
@@ -7113,7 +8225,7 @@ diff --git a/src/share/classes/sun/dyn/M
static final int
ETF_HANDLE_OR_METHOD_NAME = 0, // all available data (immediate MH or method)
ETF_DIRECT_HANDLE = 1, // ultimate method handle (will be a DMH, may be self)
-@@ -216,6 +216,7 @@
+@@ -216,6 +215,7 @@
|(1<<OP_ROT_ARGS)
|(1<<OP_DUP_ARGS)
|(1<<OP_DROP_ARGS)
@@ -7124,19 +8236,43 @@ diff --git a/src/share/classes/sun/dyn/M
diff --git a/src/share/classes/sun/dyn/MethodTypeImpl.java b/src/share/classes/sun/dyn/MethodTypeImpl.java
--- a/src/share/classes/sun/dyn/MethodTypeImpl.java
+++ b/src/share/classes/sun/dyn/MethodTypeImpl.java
-@@ -56,6 +56,7 @@
+@@ -56,8 +56,8 @@
// Cached adapter information:
/*lazy*/ ToGeneric toGeneric; // convert cs. with prims to w/o
/*lazy*/ FromGeneric fromGeneric; // convert cs. w/o prims to with
+ /*lazy*/ SpreadGeneric[] spreadGeneric; // expand one argument to many
/*lazy*/ FilterGeneric filterGeneric; // convert argument(s) on the fly
- ///*lazy*/ Invokers invokers; // cache of handy higher-order adapters
-
+- ///*lazy*/ Invokers invokers; // cache of handy higher-order adapters
+
+ public MethodType erasedType() {
+ return erasedType;
+@@ -68,7 +68,7 @@
+ }
+
+ /** Access methods for the internals of MethodType, supplied to
+- * MethodTypeForm as a trusted agent.
++ * MethodTypeImpl as a trusted agent.
+ */
+ static public interface MethodTypeFriend {
+ Class<?>[] ptypes(MethodType mt);
+@@ -378,10 +378,10 @@
+ static MethodTypeImpl findForm(MethodType mt) {
+ MethodType erased = canonicalize(mt, ERASE, ERASE);
+ if (erased == null) {
+- // It is already erased. Make a new MethodTypeForm.
++ // It is already erased. Make a new MethodTypeImpl.
+ return METHOD_TYPE_FRIEND.newMethodTypeForm(mt);
+ } else {
+- // Share the MethodTypeForm with the erased version.
++ // Share the MethodTypeImpl with the erased version.
+ return METHOD_TYPE_FRIEND.form(erased);
+ }
+ }
diff --git a/src/share/classes/sun/dyn/SpreadGeneric.java b/src/share/classes/sun/dyn/SpreadGeneric.java
new file mode 100644
--- /dev/null
+++ b/src/share/classes/sun/dyn/SpreadGeneric.java
-@@ -0,0 +1,677 @@
+@@ -0,0 +1,682 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -7361,6 +8497,11 @@ new file mode 100644
+ */
+ protected final SpreadGeneric outer;
+ protected final MethodHandle target; // (any**N) => R
++
++ @Override
++ public String toString() {
++ return target.toString();
++ }
+
+ static final MethodHandle NO_ENTRY = ValueConversions.identity();
+
@@ -7826,7 +8967,59 @@ diff --git a/src/share/classes/sun/dyn/T
* that implement members of the erasure-family of the given erased type.
*/
private ToGeneric(MethodType entryType) {
-@@ -157,8 +157,8 @@
+@@ -111,19 +111,38 @@
+ // primitive arguments according to their "raw" types int/long
+ MethodType intsAtEnd = MethodTypeImpl.of(primsAtEnd).primsAsInts();
+ ad = findAdapter(rawEntryTypeInit = intsAtEnd);
+- if (ad == null) {
++ MethodHandle rawEntryPoint;
++ if (ad != null) {
++ rawEntryPoint = ad.prototypeEntryPoint();
++ } else {
+ // Perhaps the adapter is available only for longs.
+ // If so, we can use it, but there will have to be a little
+ // more stack motion on each call.
+ MethodType longsAtEnd = MethodTypeImpl.of(primsAtEnd).primsAsLongs();
+ ad = findAdapter(rawEntryTypeInit = longsAtEnd);
+- if (ad == null) {
++ if (ad != null) {
++ MethodType eptWithLongs = longsAtEnd.insertParameterType(0, ad.getClass());
++ MethodType eptWithInts = intsAtEnd.insertParameterType(0, ad.getClass());
++ rawEntryPoint = ad.prototypeEntryPoint();
++ MethodType midType = eptWithLongs; // will change longs to ints
++ for (int i = 0, nargs = midType.parameterCount(); i < nargs; i++) {
++ if (midType.parameterType(i) != eptWithInts.parameterType(i)) {
++ assert(midType.parameterType(i) == long.class);
++ assert(eptWithInts.parameterType(i) == int.class);
++ MethodType nextType = midType.changeParameterType(i, int.class);
++ rawEntryPoint = MethodHandle.convertArguments(Access.TOKEN,
++ rawEntryPoint, nextType, midType, null);
++ midType = nextType;
++ }
++ }
++ assert(midType == eptWithInts);
++ } else {
+ // If there is no statically compiled adapter,
+ // build one by means of dynamic bytecode generation.
+ ad = buildAdapterFromBytecodes(rawEntryTypeInit = intsAtEnd);
++ rawEntryPoint = ad.prototypeEntryPoint();
+ }
+ }
+- MethodHandle rawEntryPoint = ad.prototypeEntryPoint();
+ MethodType tepType = entryType.insertParameterType(0, ad.getClass());
+ this.entryPoint =
+ AdapterMethodHandle.makeRawRetypeOnly(Access.TOKEN, tepType, rawEntryPoint);
+@@ -133,8 +152,7 @@
+ this.returnConversion = computeReturnConversion(entryType, rawEntryTypeInit, false);
+ this.rawEntryType = rawEntryTypeInit;
+ this.adapter = ad;
+- this.invoker = makeRawArgumentFilter(invoker0,
+- rawEntryPoint.type().dropParameterType(0), entryType);
++ this.invoker = makeRawArgumentFilter(invoker0, rawEntryTypeInit, entryType);
+ }
+
+ /** A generic argument list will be created by a call of type 'raw'.
+@@ -157,8 +175,8 @@
if (filteredInvoker == null) throw new UnsupportedOperationException("NYI");
}
MethodHandle reboxer = ValueConversions.rebox(dst, false);
@@ -7837,7 +9030,7 @@ diff --git a/src/share/classes/sun/dyn/T
}
if (filteredInvoker == null) return invoker;
return AdapterMethodHandle.makeRetypeOnly(Access.TOKEN, invoker.type(), filteredInvoker);
-@@ -283,7 +283,10 @@
+@@ -283,7 +301,10 @@
try {
return ctor.newInstance(entryPoint);
} catch (IllegalArgumentException ex) {
@@ -7849,7 +9042,19 @@ diff --git a/src/share/classes/sun/dyn/T
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
}
-@@ -344,33 +347,33 @@
+@@ -317,6 +338,11 @@
+ protected final MethodHandle target; // Object... -> Object
+ protected final MethodHandle convert; // Object -> R
+
++ @Override
++ public String toString() {
++ return target.toString();
++ }
++
+ protected boolean isPrototype() { return target == null; }
+ /* Prototype constructor. */
+ protected Adapter(MethodHandle entryPoint) {
+@@ -344,33 +370,33 @@
// { return new ThisType(entryPoint, convert, target); }
// Code to run when the arguments (<= 4) have all been boxed.
@@ -7898,7 +9103,7 @@ diff --git a/src/share/classes/sun/dyn/T
static private final String CLASS_PREFIX; // "sun.dyn.ToGeneric$"
static {
-@@ -397,25 +400,25 @@
+@@ -397,25 +423,25 @@
protected A1(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
protected A1(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
protected A1 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A1(e, i, c, t); }
@@ -7943,7 +9148,7 @@ diff --git a/src/share/classes/sun/dyn/T
}
// */
-@@ -435,13 +438,13 @@
+@@ -435,13 +461,13 @@
" protected @cat@(MethodHandle entryPoint) { super(entryPoint); } // to build prototype",
" protected @cat@(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }",
" protected @cat@ makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new @cat@(e, i, c, t); }",
@@ -7960,7 +9165,7 @@ diff --git a/src/share/classes/sun/dyn/T
" //@end-R@",
" //@end-Tv@",
" }",
-@@ -595,424 +598,424 @@
+@@ -595,424 +621,424 @@
protected A0(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
protected A0(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
protected A0 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A0(e, i, c, t); }
@@ -8805,7 +10010,109 @@ diff --git a/src/share/classes/sun/dyn/u
EnumMap<Wrapper, MethodHandle>[] caches
= (EnumMap<Wrapper, MethodHandle>[]) new EnumMap[n]; // unchecked warning expected here
for (int i = 0; i < n; i++)
-@@ -543,7 +547,7 @@
+@@ -305,29 +309,47 @@
+
+ /// Kludges for when raw values get accidentally boxed.
+
++ static int unboxRawInteger(Object x) {
++ if (x instanceof Integer)
++ return unboxInteger(x);
++ else
++ return (int) unboxLong(x);
++ }
++
++ static Integer reboxRawInteger(Object x) {
++ if (x instanceof Integer)
++ return (Integer) x;
++ else
++ return (int) unboxLong(x);
++ }
++
+ static Byte reboxRawByte(Object x) {
+ if (x instanceof Byte) return (Byte) x;
+- return boxByteRaw(unboxInteger(x));
++ return boxByteRaw(unboxRawInteger(x));
+ }
+
+ static Short reboxRawShort(Object x) {
+ if (x instanceof Short) return (Short) x;
+- return boxShortRaw(unboxInteger(x));
++ return boxShortRaw(unboxRawInteger(x));
+ }
+
+ static Boolean reboxRawBoolean(Object x) {
+ if (x instanceof Boolean) return (Boolean) x;
+- return boxBooleanRaw(unboxInteger(x));
++ return boxBooleanRaw(unboxRawInteger(x));
+ }
+
+ static Character reboxRawCharacter(Object x) {
+ if (x instanceof Character) return (Character) x;
+- return boxCharacterRaw(unboxInteger(x));
++ return boxCharacterRaw(unboxRawInteger(x));
+ }
+
+ static Float reboxRawFloat(Object x) {
+ if (x instanceof Float) return (Float) x;
+- return boxFloatRaw(unboxInteger(x));
++ return boxFloatRaw(unboxRawInteger(x));
++ }
++
++ static Long reboxRawLong(Object x) {
++ return (Long) x; //never a rebox
+ }
+
+ static Double reboxRawDouble(Object x) {
+@@ -343,6 +365,15 @@
+ private static final EnumMap<Wrapper, MethodHandle>[]
+ REBOX_CONVERSIONS = newWrapperCaches(2);
+
++ /**
++ * Becase we normalize primitive types to reduce the number of signatures,
++ * primitives are sometimes manipulated under an "erased" type,
++ * either int (for types other than long/double) or long (for all types).
++ * When the erased primitive value is then boxed into an Integer or Long,
++ * the final boxed primitive is sometimes required. This transformation
++ * is called a "rebox". It takes an Integer or Long and produces some
++ * other boxed value.
++ */
+ public static MethodHandle rebox(Wrapper wrap, boolean exact) {
+ EnumMap<Wrapper, MethodHandle> cache = REBOX_CONVERSIONS[exact?1:0];
+ MethodHandle mh = cache.get(wrap);
+@@ -355,9 +386,6 @@
+ mh = IDENTITY; break;
+ case VOID:
+ throw new IllegalArgumentException("cannot rebox a void");
+- case INT: case LONG:
+- mh = cast(wrap.wrapperType(), exact);
+- break;
+ }
+ if (mh != null) {
+ cache.put(wrap, mh);
+@@ -384,13 +412,21 @@
+ /// Width-changing conversions between int and long.
+
+ static long widenInt(int x) {
+- return x;
++ return (long) x;
++ }
++
++ static Long widenBoxedInt(Integer x) {
++ return (long)(int)x;
+ }
+
+ static int narrowLong(long x) {
+ return (int) x;
+ }
+
++ static Integer narrowBoxedLong(Long x) {
++ return (int)(long) x;
++ }
++
+ /// Constant functions
+
+ static void ignore(Object x) {
+@@ -543,7 +579,7 @@
else if (VerifyType.isNullType(type))
mh = ALWAYS_NULL;
else
@@ -8814,7 +10121,7 @@ diff --git a/src/share/classes/sun/dyn/u
if (exact) {
MethodType xmt = MethodType.make(type, Object.class);
mh = AdapterMethodHandle.makeRawRetypeOnly(IMPL_TOKEN, xmt, mh);
-@@ -560,4 +564,127 @@
+@@ -560,4 +596,127 @@
private static MethodHandle retype(MethodType type, MethodHandle mh) {
return AdapterMethodHandle.makeRetypeOnly(IMPL_TOKEN, type, mh);
}