diff -r faedb20bdcbb -r 16c1792b2ee6 jdk/src/share/classes/java/dyn/MethodHandle.java --- a/jdk/src/share/classes/java/dyn/MethodHandle.java Thu Jun 17 16:28:11 2010 -0700 +++ b/jdk/src/share/classes/java/dyn/MethodHandle.java Fri Jun 18 15:23:57 2010 -0700 @@ -34,32 +34,34 @@ import static sun.dyn.MemberName.newIllegalArgumentException; // utility /** - * A method handle is a typed reference to the entry point of a method. + * A method handle is a typed, directly executable reference to a method, + * constructor, field, or similar low-level operation, with optional + * conversion or substitution of arguments or return values. *

* Method handles are strongly typed according to signature. * They are not distinguished by method name or enclosing class. * A method handle must be invoked under a signature which exactly matches - * the method handle's own type. + * the method handle's own {@link MethodType method type}. *

- * Every method handle confesses its type via the type accessor. + * Every method handle confesses its type via the {@code type} accessor. * The structure of this type is a series of classes, one of which is - * the return type of the method (or void.class if none). + * the return type of the method (or {@code void.class} if none). *

* Every method handle appears as an object containing a method named - * invoke, whose signature exactly matches + * {@code invoke}, whose signature exactly matches * the method handle's type. * A Java method call expression, which compiles to an - * invokevirtual instruction, + * {@code invokevirtual} instruction, * can invoke this method from Java source code. *

* Every call to a method handle specifies an intended method type, * which must exactly match the type of the method handle. - * (The type is specified in the invokevirtual instruction, + * (The type is specified in the {@code invokevirtual} instruction, * via a {@code CONSTANT_NameAndType} constant pool entry.) * The call looks within the receiver object for a method - * named invoke of the intended method type. + * named {@code invoke} of the intended method type. * The call fails with a {@link WrongMethodTypeException} - * if the method does not exist, even if there is an invoke + * if the method does not exist, even if there is an {@code invoke} * method of a closely similar signature. * As with other kinds * of methods in the JVM, signature matching during method linkage @@ -76,13 +78,13 @@ * They should not be passed to untrusted code. *

* Bytecode in an extended JVM can directly call a method handle's - * invoke from an invokevirtual instruction. - * The receiver class type must be MethodHandle and the method name - * must be invoke. The signature of the invocation + * {@code invoke} from an {@code invokevirtual} instruction. + * The receiver class type must be {@code MethodHandle} and the method name + * must be {@code invoke}. The signature of the invocation * (after resolving symbolic type names) must exactly match the method type * of the target method. *

- * Every invoke method always throws {@link Exception}, + * Every {@code invoke} method always throws {@link Exception}, * which is to say that there is no static restriction on what a method handle * can throw. Since the JVM does not distinguish between checked * and unchecked exceptions (other than by their class, of course), @@ -92,11 +94,11 @@ * throw {@code Exception}, or else must catch all checked exceptions locally. *

* Bytecode in an extended JVM can directly obtain a method handle - * for any accessible method from a ldc instruction - * which refers to a CONSTANT_Methodref or - * CONSTANT_InterfaceMethodref constant pool entry. + * for any accessible method from a {@code ldc} instruction + * which refers to a {@code CONSTANT_Methodref} or + * {@code CONSTANT_InterfaceMethodref} constant pool entry. *

- * All JVMs can also use a reflective API called MethodHandles + * All JVMs can also use a reflective API called {@code MethodHandles} * for creating and calling method handles. *

* A method reference may refer either to a static or non-static method. @@ -104,7 +106,7 @@ * receiver argument, prepended before any other arguments. * In the method handle's type, the initial receiver argument is typed * according to the class under which the method was initially requested. - * (E.g., if a non-static method handle is obtained via ldc, + * (E.g., if a non-static method handle is obtained via {@code ldc}, * the type of the receiver is the class named in the constant pool entry.) *

* When a method handle to a virtual method is invoked, the method is @@ -113,38 +115,38 @@ * A non-virtual method handles to a specific virtual method implementation * can also be created. These do not perform virtual lookup based on * receiver type. Such a method handle simulates the effect of - * an invokespecial instruction to the same method. + * an {@code invokespecial} instruction to the same method. *

* Here are some examples of usage: *

- * Object x, y; String s; int i;
- * MethodType mt; MethodHandle mh;
- * MethodHandles.Lookup lookup = MethodHandles.lookup();
- * // mt is {(char,char) => String}
- * 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.<String>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[] => List}
- * mt = MethodType.make(java.util.List.class, Object[].class);
- * mh = lookup.findStatic(java.util.Arrays.class, "asList", mt);
- * // mt is {(Object,Object,Object) => Object}
- * mt = MethodType.makeGeneric(3);
- * mh = MethodHandles.collectArguments(mh, mt);
- * // mt is {(Object,Object,Object) => Object}
- * // (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
- * x = mh.invoke((Object)1, (Object)2, (Object)3);
- * assert(x.equals(java.util.Arrays.asList(1,2,3)));
- * // mt is { => int}
- * mt = MethodType.make(int.class);
- * mh = lookup.findVirtual(java.util.List.class, "size", mt);
- * // (Ljava/util/List;)I
- * i = mh.<int>invoke(java.util.Arrays.asList(1,2,3));
- * assert(i == 3);
+Object x, y; String s; int i;
+MethodType mt; MethodHandle mh;
+MethodHandles.Lookup lookup = MethodHandles.lookup();
+// mt is {(char,char) => String}
+mt = MethodType.methodType(String.class, char.class, char.class);
+mh = lookup.findVirtual(String.class, "replace", mt);
+// (Ljava/lang/String;CC)Ljava/lang/String;
+s = mh.<String>invokeExact("daddy",'d','n');
+assert(s.equals("nanny"));
+// weakly typed invocation (using MHs.invoke)
+s = (String) mh.invokeVarargs("sappy", 'p', 'v');
+assert(s.equals("savvy"));
+// mt is {Object[] => List}
+mt = MethodType.methodType(java.util.List.class, Object[].class);
+mh = lookup.findStatic(java.util.Arrays.class, "asList", mt);
+// mt is {(Object,Object,Object) => Object}
+mt = MethodType.genericMethodType(3);
+mh = MethodHandles.collectArguments(mh, mt);
+// mt is {(Object,Object,Object) => Object}
+// (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+x = mh.invokeExact((Object)1, (Object)2, (Object)3);
+assert(x.equals(java.util.Arrays.asList(1,2,3)));
+// mt is { => int}
+mt = MethodType.methodType(int.class);
+mh = lookup.findVirtual(java.util.List.class, "size", mt);
+// (Ljava/util/List;)I
+i = mh.<int>invokeExact(java.util.Arrays.asList(1,2,3));
+assert(i == 3);
  * 
* Each of the above calls generates a single invokevirtual instruction * with the name {@code invoke} and the type descriptors indicated in the comments. @@ -167,6 +169,14 @@ * those of multiple arities. It is impossible to represent such * genericity with a Java type parameter. * + * Signature polymorphic methods in this class appear to be documented + * as having type parameters for return types and a parameter, but that is + * merely a documentation convention. These type parameters do + * not play a role in type-checking method handle invocations. + *

+ * Note: Like classes and strings, method handles that correspond directly + * to fields and methods can be represented directly as constants to be + * loaded by {@code ldc} bytecodes. * * @see MethodType * @see MethodHandles @@ -180,7 +190,15 @@ private static Access IMPL_TOKEN = Access.getToken(); // interface MethodHandle - // { MethodType type(); public R invoke(A...) throws X; } + // { MethodType type(); public R invokeExact(A...) throws X; } + + /** + * Internal marker interface which distinguishes (to the Java compiler) + * those methods which are signature polymorphic. + */ + @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD,java.lang.annotation.ElementType.TYPE}) + @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) + @interface PolymorphicSignature { } private MethodType type; @@ -232,85 +250,38 @@ return MethodHandleImpl.getNameString(IMPL_TOKEN, this); } - //// First draft of the "Method Handle Kernel API" discussed at the JVM Language Summit, 9/2009. + //// This is the "Method Handle Kernel API" discussed at the JVM Language Summit, 9/2009. //// Implementations here currently delegate to statics in MethodHandles. Some of those statics //// will be deprecated. Others will be kept as "algorithms" to supply degrees of freedom //// not present in the Kernel API. /** * PROVISIONAL API, WORK IN PROGRESS: - * Perform an exact invocation. The signature at the call site of {@code invokeExact} must + * Invoke the method handle, allowing any caller signature, but requiring an exact signature match. + * The signature at the call site of {@code invokeExact} must * exactly match this method handle's {@code type}. * No conversions are allowed on arguments or return values. - * This is not yet implemented, pending required compiler and JVM support. */ - public final T invokeExact(Object... arguments) throws Throwable { - // This is an approximate implementation, which discards the caller's signature and refuses the call. - throw new InternalError("not yet implemented"); - } + public final native @PolymorphicSignature R invokeExact(A... args) throws Throwable; + + // FIXME: remove this transitional form + /** @deprecated transitional form defined in EDR but removed in PFD */ + public final native @PolymorphicSignature R invoke(A... args) throws Throwable; /** * PROVISIONAL API, WORK IN PROGRESS: - * Perform a generic invocation. The signature at the call site of {@code invokeExact} must + * Invoke the method handle, allowing any caller signature, + * and performing simple conversions for arguments and return types. + * The signature at the call site of {@code invokeGeneric} must * have the same arity as this method handle's {@code type}. * The same conversions are allowed on arguments or return values as are supported by * by {@link MethodHandles#convertArguments}. * If the call site signature exactly matches this method handle's {@code type}, * the call proceeds as if by {@link #invokeExact}. - * This is not fully implemented, pending required compiler and JVM support. */ - // This is an approximate implementation, which discards the caller's signature. - // When it is made signature polymorphic, the overloadings will disappear. - public final T invokeGeneric() throws Throwable { - MethodHandle invoker = invokers(this.type()).genericInvoker(); - return invoker.invoke(this); - } - public final T invokeGeneric(Object a0) throws Throwable { - MethodHandle invoker = invokers(this.type()).genericInvoker(); - return invoker.invoke(this, a0); - } - public final T invokeGeneric(Object a0, Object a1) throws Throwable { - MethodHandle invoker = invokers(this.type()).genericInvoker(); - return invoker.invoke(this, a0, a1); - } - public final T invokeGeneric(Object a0, Object a1, Object a2) throws Throwable { - MethodHandle invoker = invokers(this.type()).genericInvoker(); - return invoker.invoke(this, a0, a1, a2); - } - public final T invokeGeneric(Object a0, Object a1, Object a2, Object a3) throws Throwable { - MethodHandle invoker = invokers(this.type()).genericInvoker(); - return invoker.invoke(this, a0, a1, a2, a3); - } - public final T invokeGeneric(Object a0, Object a1, Object a2, Object a3, - Object a4) throws Throwable { - MethodHandle invoker = invokers(this.type()).genericInvoker(); - return invoker.invoke(this, a0, a1, a2, a3, a4); - } - public final T invokeGeneric(Object a0, Object a1, Object a2, Object a3, - Object a4, Object a5) throws Throwable { - MethodHandle invoker = invokers(this.type()).genericInvoker(); - return invoker.invoke(this, a0, a1, a2, a3, a4, a5); - } - public final T invokeGeneric(Object a0, Object a1, Object a2, Object a3, - Object a4, Object a5, Object a6) throws Throwable { - MethodHandle invoker = invokers(this.type()).genericInvoker(); - return invoker.invoke(this, a0, a1, a2, a3, a4, a5, a6); - } - public final T invokeGeneric(Object a0, Object a1, Object a2, Object a3, - Object a4, Object a5, Object a6, Object a7) throws Throwable { - MethodHandle invoker = invokers(this.type()).genericInvoker(); - return invoker.invoke(this, a0, a1, a2, a3, a4, a5, a6, a7); - } - public final T invokeGeneric(Object a0, Object a1, Object a2, Object a3, - Object a4, Object a5, Object a6, Object a7, Object a8) throws Throwable { - MethodHandle invoker = invokers(this.type()).genericInvoker(); - return invoker.invoke(this, a0, a1, a2, a3, a4, a5, a6, a7, a8); - } - public final T invokeGeneric(Object a0, Object a1, Object a2, Object a3, - Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) throws Throwable { - MethodHandle invoker = invokers(this.type()).genericInvoker(); - return invoker.invoke(this, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); - } + public final native @PolymorphicSignature R invokeGeneric(A... args) throws Throwable; + + // ?? public final native @PolymorphicSignature R invokeVarargs(A args, V[] varargs) throws Throwable; /** * PROVISIONAL API, WORK IN PROGRESS: @@ -341,47 +312,47 @@ * This call is equivalent to the following code: *

      *   MethodHandle invoker = MethodHandles.genericInvoker(this.type(), 0, true);
-     *   Object result = invoker.invoke(this, arguments);
+     *   Object result = invoker.invokeExact(this, arguments);
      * 
* @param arguments the arguments to pass to the target * @return the result returned by the target * @see MethodHandles#genericInvoker */ - public final Object invokeVarargs(Object[] arguments) throws Throwable { + public final Object invokeVarargs(Object... arguments) throws Throwable { int argc = arguments == null ? 0 : arguments.length; MethodType type = type(); if (argc <= 10) { MethodHandle invoker = MethodHandles.invokers(type).genericInvoker(); switch (argc) { - case 0: return invoker.invoke(this); - case 1: return invoker.invoke(this, + case 0: return invoker.invokeExact(this); + case 1: return invoker.invokeExact(this, arguments[0]); - case 2: return invoker.invoke(this, + case 2: return invoker.invokeExact(this, arguments[0], arguments[1]); - case 3: return invoker.invoke(this, + case 3: return invoker.invokeExact(this, arguments[0], arguments[1], arguments[2]); - case 4: return invoker.invoke(this, + case 4: return invoker.invokeExact(this, arguments[0], arguments[1], arguments[2], arguments[3]); - case 5: return invoker.invoke(this, + case 5: return invoker.invokeExact(this, arguments[0], arguments[1], arguments[2], arguments[3], arguments[4]); - case 6: return invoker.invoke(this, + case 6: return invoker.invokeExact(this, arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5]); - case 7: return invoker.invoke(this, + case 7: return invoker.invokeExact(this, arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5], arguments[6]); - case 8: return invoker.invoke(this, + case 8: return invoker.invokeExact(this, arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5], arguments[6], arguments[7]); - case 9: return invoker.invoke(this, + case 9: return invoker.invokeExact(this, arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5], arguments[6], arguments[7], arguments[8]); - case 10: return invoker.invoke(this, + case 10: return invoker.invokeExact(this, arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5], arguments[6], arguments[7], arguments[8], @@ -391,7 +362,7 @@ // more than ten arguments get boxed in a varargs list: MethodHandle invoker = MethodHandles.invokers(type).varargsInvoker(0); - return invoker.invoke(this, arguments); + return invoker.invokeExact(this, arguments); } /** Equivalent to {@code invokeVarargs(arguments.toArray())}. */ public final Object invokeVarargs(java.util.List arguments) throws Throwable {