Merge
authorjcoomes
Fri, 27 May 2011 19:03:03 -0700
changeset 9753 43aa07d93e7f
parent 9751 ce1f88925950 (current diff)
parent 9752 88ab34b6da6d (diff)
child 9758 eb03580ef487
child 9779 e3a8fbcb21fb
Merge
--- a/jdk/src/share/classes/java/lang/BootstrapMethodError.java	Thu May 26 20:20:03 2011 -0700
+++ b/jdk/src/share/classes/java/lang/BootstrapMethodError.java	Fri May 27 19:03:03 2011 -0700
@@ -39,14 +39,14 @@
     private static final long serialVersionUID = 292L;
 
     /**
-     * Constructs an {@code BootstrapMethodError} with no detail message.
+     * Constructs a {@code BootstrapMethodError} with no detail message.
      */
     public BootstrapMethodError() {
         super();
     }
 
     /**
-     * Constructs an {@code BootstrapMethodError} with the specified
+     * Constructs a {@code BootstrapMethodError} with the specified
      * detail message.
      *
      * @param s the detail message.
--- a/jdk/src/share/classes/java/lang/ClassValue.java	Thu May 26 20:20:03 2011 -0700
+++ b/jdk/src/share/classes/java/lang/ClassValue.java	Fri May 27 19:03:03 2011 -0700
@@ -39,6 +39,13 @@
  */
 public abstract class ClassValue<T> {
     /**
+     * Sole constructor.  (For invocation by subclass constructors, typically
+     * implicit.)
+     */
+    protected ClassValue() {
+    }
+
+    /**
      * Computes the given class's derived value for this {@code ClassValue}.
      * <p>
      * This method will be invoked within the first thread that accesses
@@ -100,7 +107,7 @@
      * If this value is subsequently {@linkplain #get read} for the same class,
      * its value will be reinitialized by invoking its {@link #computeValue computeValue} method.
      * This may result in an additional invocation of the
-     * {@code computeValue computeValue} method for the given class.
+     * {@code computeValue} method for the given class.
      * <p>
      * In order to explain the interaction between {@code get} and {@code remove} calls,
      * we must model the state transitions of a class value to take into account
@@ -193,6 +200,7 @@
         = new WeakHashMap<Class<?>, ClassValueMap>();
 
     private static ClassValueMap getMap(Class<?> type) {
+        type.getClass();  // test for null
         return ROOT.get(type);
     }
 
--- a/jdk/src/share/classes/java/lang/invoke/AdapterMethodHandle.java	Thu May 26 20:20:03 2011 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/AdapterMethodHandle.java	Fri May 27 19:03:03 2011 -0700
@@ -29,6 +29,8 @@
 import sun.invoke.util.Wrapper;
 import sun.invoke.util.ValueConversions;
 import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.Collections;
 import static java.lang.invoke.MethodHandleNatives.Constants.*;
 import static java.lang.invoke.MethodHandleStatics.*;
 
@@ -62,7 +64,7 @@
     // the target and change its type, instead of adding another layer.
 
     /** Can a JVM-level adapter directly implement the proposed
-     *  argument conversions, as if by MethodHandles.convertArguments?
+     *  argument conversions, as if by fixed-arity MethodHandle.asType?
      */
     static boolean canPairwiseConvert(MethodType newType, MethodType oldType, int level) {
         // same number of args, of course
@@ -92,7 +94,7 @@
     }
 
     /** Can a JVM-level adapter directly implement the proposed
-     *  argument conversion, as if by MethodHandles.convertArguments?
+     *  argument conversion, as if by fixed-arity MethodHandle.asType?
      */
     static boolean canConvertArgument(Class<?> src, Class<?> dst, int level) {
         // ? Retool this logic to use RETYPE_ONLY, CHECK_CAST, etc., as opcodes,
@@ -550,6 +552,7 @@
         int last = type.parameterCount() - 1;
         if (type.parameterType(last) != arrayType)
             target = target.asType(type.changeParameterType(last, arrayType));
+        target = target.asFixedArity();  // make sure this attribute is turned off
         return new AsVarargsCollector(target, arrayType);
     }
 
@@ -571,6 +574,11 @@
         }
 
         @Override
+        public MethodHandle asFixedArity() {
+            return target;
+        }
+
+        @Override
         public MethodHandle asType(MethodType newType) {
             MethodType type = this.type();
             int collectArg = type.parameterCount() - 1;
@@ -594,14 +602,6 @@
             cache = collector;
             return collector.asType(newType);
         }
-
-        @Override
-        public MethodHandle asVarargsCollector(Class<?> arrayType) {
-            MethodType type = this.type();
-            if (type.parameterType(type.parameterCount()-1) == arrayType)
-                return this;
-            return super.asVarargsCollector(arrayType);
-        }
     }
 
     /** Can a checkcast adapter validly convert the target to newType?
@@ -747,8 +747,31 @@
         if (!canUnboxArgument(newType, oldType, arg, convType, level))
             return null;
         MethodType castDone = newType;
-        if (!VerifyType.isNullConversion(src, boxType))
+        if (!VerifyType.isNullConversion(src, boxType)) {
+            // Examples:  Object->int, Number->int, Comparable->int; Byte->int, Character->int
+            if (level != 0) {
+                // must include additional conversions
+                if (src == Object.class || !Wrapper.isWrapperType(src)) {
+                    // src must be examined at runtime, to detect Byte, Character, etc.
+                    MethodHandle unboxMethod = (level == 1
+                                                ? ValueConversions.unbox(dst)
+                                                : ValueConversions.unboxCast(dst));
+                    long conv = makeConv(OP_COLLECT_ARGS, arg, basicType(src), basicType(dst));
+                    return new AdapterMethodHandle(target, newType, conv, unboxMethod);
+                }
+                // Example: Byte->int
+                // Do this by reformulating the problem to Byte->byte.
+                Class<?> srcPrim = Wrapper.forWrapperType(src).primitiveType();
+                MethodType midType = newType.changeParameterType(arg, srcPrim);
+                MethodHandle fixPrim; // makePairwiseConvert(midType, target, 0);
+                if (canPrimCast(midType, oldType, arg, dst))
+                    fixPrim = makePrimCast(midType, target, arg, dst);
+                else
+                    fixPrim = target;
+                return makeUnboxArgument(newType, fixPrim, arg, srcPrim, 0);
+            }
             castDone = newType.changeParameterType(arg, boxType);
+        }
         long conv = makeConv(OP_REF_TO_PRIM, arg, T_OBJECT, basicType(primType));
         MethodHandle adapter = new AdapterMethodHandle(target, castDone, conv, boxType);
         if (castDone == newType)
@@ -917,6 +940,20 @@
         if (swapArg1 == swapArg2)
             return target;
         if (swapArg1 > swapArg2) { int t = swapArg1; swapArg1 = swapArg2; swapArg2 = t; }
+        if (type2size(newType.parameterType(swapArg1)) !=
+            type2size(newType.parameterType(swapArg2))) {
+            // turn a swap into a pair of rotates:
+            // [x a b c y] => [a b c y x] => [y a b c x]
+            int argc = swapArg2 - swapArg1 + 1;
+            final int ROT = 1;
+            ArrayList<Class<?>> rot1Params = new ArrayList<Class<?>>(target.type().parameterList());
+            Collections.rotate(rot1Params.subList(swapArg1, swapArg1 + argc), -ROT);
+            MethodType rot1Type = MethodType.methodType(target.type().returnType(), rot1Params);
+            MethodHandle rot1 = makeRotateArguments(rot1Type, target, swapArg1, argc, +ROT);
+            if (argc == 2)  return rot1;
+            MethodHandle rot2 = makeRotateArguments(newType, rot1, swapArg1, argc-1, -ROT);
+            return rot2;
+        }
         if (!canSwapArguments(newType, target.type(), swapArg1, swapArg2))
             return null;
         Class<?> swapType = newType.parameterType(swapArg1);
@@ -946,7 +983,6 @@
     static boolean canRotateArguments(MethodType newType, MethodType targetType,
                 int firstArg, int argCount, int rotateBy) {
         if (!convOpSupported(OP_ROT_ARGS))  return false;
-        if (argCount <= 2)  return false;  // must be a swap, not a rotate
         rotateBy = positiveRotation(argCount, rotateBy);
         if (rotateBy == 0)  return false;  // no rotation
         if (rotateBy > MAX_ARG_ROTATION && rotateBy < argCount - MAX_ARG_ROTATION)
@@ -992,6 +1028,7 @@
         // From here on out, it assumes a single-argument shift.
         assert(MAX_ARG_ROTATION == 1);
         int srcArg, dstArg;
+        int dstSlot;
         byte basicType;
         if (chunk2Slots <= chunk1Slots) {
             // Rotate right/down N (rotateBy = +N, N small, c2 small):
@@ -999,6 +1036,7 @@
             // out arglist: [0: ...keep1 | arg1: c2 | arg1+N: c1...   | limit: keep2... ]
             srcArg = limit-1;
             dstArg = firstArg;
+            dstSlot = depth0 - chunk2Slots;
             basicType = basicType(newType.parameterType(srcArg));
             assert(chunk2Slots == type2size(basicType));
         } else {
@@ -1007,10 +1045,10 @@
             // out arglist: [0: ...keep1 | arg1: c2 ... | limit-N: c1 | limit: keep2... ]
             srcArg = firstArg;
             dstArg = limit-1;
+            dstSlot = depth2;
             basicType = basicType(newType.parameterType(srcArg));
             assert(chunk1Slots == type2size(basicType));
         }
-        int dstSlot = newType.parameterSlotDepth(dstArg + 1);
         long conv = makeSwapConv(OP_ROT_ARGS, srcArg, basicType, dstSlot);
         return new AdapterMethodHandle(target, newType, conv);
     }
--- a/jdk/src/share/classes/java/lang/invoke/BoundMethodHandle.java	Thu May 26 20:20:03 2011 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/BoundMethodHandle.java	Fri May 27 19:03:03 2011 -0700
@@ -151,7 +151,7 @@
 
     final static RuntimeException badBoundArgumentException(Object argument, MethodHandle mh, int argnum) {
         String atype = (argument == null) ? "null" : argument.getClass().toString();
-        return new WrongMethodTypeException("cannot bind "+atype+" argument to parameter #"+argnum+" of "+mh.type());
+        return new ClassCastException("cannot bind "+atype+" argument to parameter #"+argnum+" of "+mh.type());
     }
 
     @Override
--- a/jdk/src/share/classes/java/lang/invoke/CallSite.java	Thu May 26 20:20:03 2011 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/CallSite.java	Fri May 27 19:03:03 2011 -0700
@@ -111,7 +111,7 @@
     }
 
     /**
-     * Make a blank call site object, possibly equipped with an initial target method handle.
+     * Make a call site object equipped with an initial target method handle.
      * @param target the method handle which will be the initial target of the call site
      * @throws NullPointerException if the proposed target is null
      */
@@ -122,6 +122,25 @@
     }
 
     /**
+     * Make a call site object equipped with an initial target method handle.
+     * @param targetType the desired type of the call site
+     * @param createTargetHook a hook which will bind the call site to the target method handle
+     * @throws WrongMethodTypeException if the hook cannot be invoked on the required arguments,
+     *         or if the target returned by the hook is not of the given {@code targetType}
+     * @throws NullPointerException if the hook returns a null value
+     * @throws ClassCastException if the hook returns something other than a {@code MethodHandle}
+     * @throws Throwable anything else thrown by the the hook function
+     */
+    /*package-private*/
+    CallSite(MethodType targetType, MethodHandle createTargetHook) throws Throwable {
+        this(targetType);
+        ConstantCallSite selfCCS = (ConstantCallSite) this;
+        MethodHandle boundTarget = (MethodHandle) createTargetHook.invokeWithArguments(selfCCS);
+        checkTargetChange(this.target, boundTarget);
+        this.target = boundTarget;
+    }
+
+    /**
      * Returns the type of this call site's target.
      * Although targets may change, any call site's type is permanent, and can never change to an unequal type.
      * The {@code setTarget} method enforces this invariant by refusing any new target that does
@@ -129,6 +148,7 @@
      * @return the type of the current target, which is also the type of any future target
      */
     public MethodType type() {
+        // warning:  do not call getTarget here, because CCS.getTarget can throw IllegalStateException
         return target.type();
     }
 
@@ -294,8 +314,8 @@
             }  else {
                 throw new ClassCastException("bootstrap method failed to produce a CallSite");
             }
-            assert(site.getTarget() != null);
-            assert(site.getTarget().type().equals(type));
+            if (!site.getTarget().type().equals(type))
+                throw new WrongMethodTypeException("wrong type: "+site.getTarget());
         } catch (Throwable ex) {
             BootstrapMethodError bex;
             if (ex instanceof BootstrapMethodError)
--- a/jdk/src/share/classes/java/lang/invoke/ConstantCallSite.java	Thu May 26 20:20:03 2011 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/ConstantCallSite.java	Fri May 27 19:03:03 2011 -0700
@@ -32,6 +32,8 @@
  * @author John Rose, JSR 292 EG
  */
 public class ConstantCallSite extends CallSite {
+    private final boolean isFrozen;
+
     /**
      * Creates a call site with a permanent target.
      * @param target the target to be permanently associated with this call site
@@ -39,6 +41,45 @@
      */
     public ConstantCallSite(MethodHandle target) {
         super(target);
+        isFrozen = true;
+    }
+
+    /**
+     * Creates a call site with a permanent target, possibly bound to the call site itself.
+     * <p>
+     * During construction of the call site, the {@code createTargetHook} is invoked to
+     * produce the actual target, as if by a call of the form
+     * {@code (MethodHandle) createTargetHook.invoke(this)}.
+     * <p>
+     * Note that user code cannot perform such an action directly in a subclass constructor,
+     * since the target must be fixed before the {@code ConstantCallSite} constructor returns.
+     * <p>
+     * The hook is said to bind the call site to a target method handle,
+     * and a typical action would be {@code someTarget.bindTo(this)}.
+     * However, the hook is free to take any action whatever,
+     * including ignoring the call site and returning a constant target.
+     * <p>
+     * The result returned by the hook must be a method handle of exactly
+     * the same type as the call site.
+     * <p>
+     * While the hook is being called, the new {@code ConstantCallSite}
+     * object is in a partially constructed state.
+     * In this state,
+     * a call to {@code getTarget}, or any other attempt to use the target,
+     * will result in an {@code IllegalStateException}.
+     * It is legal at all times to obtain the call site's type using the {@code type} method.
+     *
+     * @param targetType the type of the method handle to be permanently associated with this call site
+     * @param createTargetHook a method handle to invoke (on the call site) to produce the call site's target
+     * @throws WrongMethodTypeException if the hook cannot be invoked on the required arguments,
+     *         or if the target returned by the hook is not of the given {@code targetType}
+     * @throws NullPointerException if the hook returns a null value
+     * @throws ClassCastException if the hook returns something other than a {@code MethodHandle}
+     * @throws Throwable anything else thrown by the the hook function
+     */
+    protected ConstantCallSite(MethodType targetType, MethodHandle createTargetHook) throws Throwable {
+        super(targetType, createTargetHook);
+        isFrozen = true;
     }
 
     /**
@@ -48,9 +89,10 @@
      * to the constructor call which created this instance.
      *
      * @return the immutable linkage state of this call site, a constant method handle
-     * @throws UnsupportedOperationException because this kind of call site cannot change its target
+     * @throws IllegalStateException if the {@code ConstantCallSite} constructor has not completed
      */
     @Override public final MethodHandle getTarget() {
+        if (!isFrozen)  throw new IllegalStateException();
         return target;
     }
 
@@ -61,7 +103,7 @@
      * @throws UnsupportedOperationException because this kind of call site cannot change its target
      */
     @Override public final void setTarget(MethodHandle ignore) {
-        throw new UnsupportedOperationException("ConstantCallSite");
+        throw new UnsupportedOperationException();
     }
 
     /**
@@ -69,6 +111,7 @@
      * Since that target will never change, this is a correct implementation
      * of {@link CallSite#dynamicInvoker CallSite.dynamicInvoker}.
      * @return the immutable linkage state of this call site, a constant method handle
+     * @throws IllegalStateException if the {@code ConstantCallSite} constructor has not completed
      */
     @Override
     public final MethodHandle dynamicInvoker() {
--- a/jdk/src/share/classes/java/lang/invoke/Invokers.java	Thu May 26 20:20:03 2011 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/Invokers.java	Fri May 27 19:03:03 2011 -0700
@@ -46,7 +46,10 @@
     // general invoker for the outgoing call
     private /*lazy*/ MethodHandle generalInvoker;
 
-    // general invoker for the outgoing call; accepts a single Object[]
+    // general invoker for the outgoing call, uses varargs
+    private /*lazy*/ MethodHandle varargsInvoker;
+
+    // general invoker for the outgoing call; accepts a trailing Object[]
     private final /*lazy*/ MethodHandle[] spreadInvokers;
 
     // invoker for an unbound callsite
@@ -67,45 +70,56 @@
     /*non-public*/ MethodHandle exactInvoker() {
         MethodHandle invoker = exactInvoker;
         if (invoker != null)  return invoker;
-        try {
-            invoker = IMPL_LOOKUP.findVirtual(MethodHandle.class, "invokeExact", targetType);
-        } catch (ReflectiveOperationException ex) {
-            throw new InternalError("JVM cannot find invoker for "+targetType);
-        }
-        assert(invokerType(targetType) == invoker.type());
+        invoker = lookupInvoker("invokeExact");
         exactInvoker = invoker;
         return invoker;
     }
 
     /*non-public*/ MethodHandle generalInvoker() {
-        MethodHandle invoker1 = exactInvoker();
         MethodHandle invoker = generalInvoker;
         if (invoker != null)  return invoker;
-        MethodType generalType = targetType.generic();
-        invoker = invoker1.asType(invokerType(generalType));
+        invoker = lookupInvoker("invoke");
         generalInvoker = invoker;
         return invoker;
     }
 
+    private MethodHandle lookupInvoker(String name) {
+        MethodHandle invoker;
+        try {
+            invoker = IMPL_LOOKUP.findVirtual(MethodHandle.class, name, targetType);
+        } catch (ReflectiveOperationException ex) {
+            throw new InternalError("JVM cannot find invoker for "+targetType);
+        }
+        assert(invokerType(targetType) == invoker.type());
+        assert(!invoker.isVarargsCollector());
+        return invoker;
+    }
+
     /*non-public*/ MethodHandle erasedInvoker() {
-        MethodHandle invoker1 = exactInvoker();
+        MethodHandle xinvoker = exactInvoker();
         MethodHandle invoker = erasedInvoker;
         if (invoker != null)  return invoker;
         MethodType erasedType = targetType.erase();
-        if (erasedType == targetType.generic())
-            invoker = generalInvoker();
-        else
-            invoker = invoker1.asType(invokerType(erasedType));
+        invoker = xinvoker.asType(invokerType(erasedType));
         erasedInvoker = invoker;
         return invoker;
     }
 
-    /*non-public*/ MethodHandle spreadInvoker(int objectArgCount) {
-        MethodHandle vaInvoker = spreadInvokers[objectArgCount];
+    /*non-public*/ MethodHandle spreadInvoker(int leadingArgCount) {
+        MethodHandle vaInvoker = spreadInvokers[leadingArgCount];
         if (vaInvoker != null)  return vaInvoker;
         MethodHandle gInvoker = generalInvoker();
-        vaInvoker = gInvoker.asSpreader(Object[].class, targetType.parameterCount() - objectArgCount);
-        spreadInvokers[objectArgCount] = vaInvoker;
+        int spreadArgCount = targetType.parameterCount() - leadingArgCount;
+        vaInvoker = gInvoker.asSpreader(Object[].class, spreadArgCount);
+        spreadInvokers[leadingArgCount] = vaInvoker;
+        return vaInvoker;
+    }
+
+    /*non-public*/ MethodHandle varargsInvoker() {
+        MethodHandle vaInvoker = varargsInvoker;
+        if (vaInvoker != null)  return vaInvoker;
+        vaInvoker = spreadInvoker(0).asType(invokerType(MethodType.genericMethodType(0, true)));
+        varargsInvoker = vaInvoker;
         return vaInvoker;
     }
 
--- a/jdk/src/share/classes/java/lang/invoke/MemberName.java	Thu May 26 20:20:03 2011 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/MemberName.java	Fri May 27 19:03:03 2011 -0700
@@ -506,8 +506,18 @@
         if (from != null)  message += ", from " + from;
         return new IllegalAccessException(message);
     }
-    public ReflectiveOperationException makeAccessException(String message) {
-        message = message + ": "+ toString();
+    private String message() {
+        if (isResolved())
+            return "no access";
+        else if (isConstructor())
+            return "no such constructor";
+        else if (isMethod())
+            return "no such method";
+        else
+            return "no such field";
+    }
+    public ReflectiveOperationException makeAccessException() {
+        String message = message() + ": "+ toString();
         if (isResolved())
             return new IllegalAccessException(message);
         else if (isConstructor())
@@ -641,7 +651,7 @@
             MemberName result = resolveOrNull(m, searchSupers, lookupClass);
             if (result != null)
                 return result;
-            ReflectiveOperationException ex = m.makeAccessException("no access");
+            ReflectiveOperationException ex = m.makeAccessException();
             if (ex instanceof IllegalAccessException)  throw (IllegalAccessException) ex;
             throw nsmClass.cast(ex);
         }
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandle.java	Thu May 26 20:20:03 2011 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandle.java	Fri May 27 19:03:03 2011 -0700
@@ -41,12 +41,12 @@
  * and {@linkplain java.lang.invoke.MethodHandles#filterArguments substitution}.
  *
  * <h3>Method handle contents</h3>
- * Method handles are dynamically and strongly typed according to type descriptor.
- * They are not distinguished by the name or defining class of their underlying methods.
- * A method handle must be invoked using type descriptor which matches
- * the method handle's own {@linkplain #type method type}.
+ * Method handles are dynamically and strongly typed according to their parameter and return types.
+ * They are not distinguished by the name or the defining class of their underlying methods.
+ * A method handle must be invoked using a symbolic type descriptor which matches
+ * the method handle's own {@linkplain #type type descriptor}.
  * <p>
- * Every method handle reports its type via the {@link #type type} accessor.
+ * Every method handle reports its type descriptor via the {@link #type type} accessor.
  * This type descriptor is a {@link java.lang.invoke.MethodType MethodType} object,
  * whose structure is a series of classes, one of which is
  * the return type of the method (or {@code void.class} if none).
@@ -83,7 +83,7 @@
  * From the viewpoint of source code, these methods can take any arguments
  * and their result can be cast to any return type.
  * Formally this is accomplished by giving the invoker methods
- * {@code Object} return types and variable-arity {@code Object} arguments,
+ * {@code Object} return types and variable arity {@code Object} arguments,
  * but they have an additional quality called <em>signature polymorphism</em>
  * which connects this freedom of invocation directly to the JVM execution stack.
  * <p>
@@ -93,17 +93,17 @@
  * and may not perform method invocation conversions on the arguments.
  * Instead, it must push them on the stack according to their own unconverted types.
  * The method handle object itself is pushed on the stack before the arguments.
- * The compiler then calls the method handle with a type descriptor which
+ * The compiler then calls the method handle with a symbolic type descriptor which
  * describes the argument and return types.
  * <p>
- * To issue a complete type descriptor, the compiler must also determine
+ * To issue a complete symbolic type descriptor, the compiler must also determine
  * the return type.  This is based on a cast on the method invocation expression,
  * if there is one, or else {@code Object} if the invocation is an expression
  * or else {@code void} if the invocation is a statement.
  * The cast may be to a primitive type (but not {@code void}).
  * <p>
  * As a corner case, an uncasted {@code null} argument is given
- * a type descriptor of {@code java.lang.Void}.
+ * a symbolic type descriptor of {@code java.lang.Void}.
  * The ambiguity with the type {@code Void} is harmless, since there are no references of type
  * {@code Void} except the null reference.
  *
@@ -112,16 +112,16 @@
  * it is linked, by symbolically resolving the names in the instruction
  * and verifying that the method call is statically legal.
  * This is true of calls to {@code invokeExact} and {@code invoke}.
- * In this case, the type descriptor emitted by the compiler is checked for
+ * In this case, the symbolic type descriptor emitted by the compiler is checked for
  * correct syntax and names it contains are resolved.
  * Thus, an {@code invokevirtual} instruction which invokes
  * a method handle will always link, as long
- * as the type descriptor is syntactically well-formed
+ * as the symbolic type descriptor is syntactically well-formed
  * and the types exist.
  * <p>
  * When the {@code invokevirtual} is executed after linking,
  * the receiving method handle's type is first checked by the JVM
- * to ensure that it matches the descriptor.
+ * to ensure that it matches the symbolic type descriptor.
  * If the type match fails, it means that the method which the
  * caller is invoking is not present on the individual
  * method handle being invoked.
@@ -138,7 +138,7 @@
  * (or other behavior, as the case may be).
  * <p>
  * A call to plain {@code invoke} works the same as a call to
- * {@code invokeExact}, if the type descriptor specified by the caller
+ * {@code invokeExact}, if the symbolic type descriptor specified by the caller
  * exactly matches the method handle's own type.
  * If there is a type mismatch, {@code invoke} attempts
  * to adjust the type of the receiving method handle,
@@ -165,9 +165,9 @@
  * method type matching takes into account both types names and class loaders.
  * Thus, even if a method handle {@code M} is created in one
  * class loader {@code L1} and used in another {@code L2},
- * method handle calls are type-safe, because the caller's type
+ * method handle calls are type-safe, because the caller's symbolic type
  * descriptor, as resolved in {@code L2},
- * is matched against the original callee method's type descriptor,
+ * is matched against the original callee method's symbolic type descriptor,
  * as resolved in {@code L1}.
  * The resolution in {@code L1} happens when {@code M} is created
  * and its type is assigned, while the resolution in {@code L2} happens
@@ -243,24 +243,24 @@
 mh = lookup.findVirtual(String.class, "replace", mt);
 s = (String) mh.invokeExact("daddy",'d','n');
 // invokeExact(Ljava/lang/String;CC)Ljava/lang/String;
-assert(s.equals("nanny"));
+assertEquals(s, "nanny");
 // weakly typed invocation (using MHs.invoke)
 s = (String) mh.invokeWithArguments("sappy", 'p', 'v');
-assert(s.equals("savvy"));
+assertEquals(s, "savvy");
 // mt is (Object[])List
 mt = MethodType.methodType(java.util.List.class, Object[].class);
 mh = lookup.findStatic(java.util.Arrays.class, "asList", mt);
 assert(mh.isVarargsCollector());
 x = mh.invoke("one", "two");
 // invoke(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;
-assert(x.equals(java.util.Arrays.asList("one","two")));
+assertEquals(x, java.util.Arrays.asList("one","two"));
 // mt is (Object,Object,Object)Object
 mt = MethodType.genericMethodType(3);
 mh = mh.asType(mt);
 x = mh.invokeExact((Object)1, (Object)2, (Object)3);
 // invokeExact(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
-assert(x.equals(java.util.Arrays.asList(1,2,3)));
-// mt is int()
+assertEquals(x, java.util.Arrays.asList(1,2,3));
+// mt is ()int
 mt = MethodType.methodType(int.class);
 mh = lookup.findVirtual(java.util.List.class, "size", mt);
 i = (int) mh.invokeExact(java.util.Arrays.asList(1,2,3));
@@ -273,7 +273,10 @@
  * </pre></blockquote>
  * Each of the above calls to {@code invokeExact} or plain {@code invoke}
  * generates a single invokevirtual instruction with
- * the type descriptor indicated in the following comment.
+ * the symbolic type descriptor indicated in the following comment.
+ * In these examples, the helper method {@code assertEquals} is assumed to
+ * be a method which calls {@link Objects.equals java.util.Objects#equals}
+ * on its arguments, and asserts that the result is true.
  *
  * <h3>Exceptions</h3>
  * The methods {@code invokeExact} and {@code invoke} are declared
@@ -284,7 +287,7 @@
  * there is no particular effect on bytecode shape from ascribing
  * checked exceptions to method handle invocations.  But in Java source
  * code, methods which perform method handle calls must either explicitly
- * throw {@code java.lang.Throwable Throwable}, or else must catch all
+ * throw {@code Throwable}, or else must catch all
  * throwables locally, rethrowing only those which are legal in the context,
  * and wrapping ones which are illegal.
  *
@@ -292,77 +295,26 @@
  * The unusual compilation and linkage behavior of
  * {@code invokeExact} and plain {@code invoke}
  * is referenced by the term <em>signature polymorphism</em>.
- * A signature polymorphic method is one which can operate with
+ * As defined in the Java Language Specification,
+ * a signature polymorphic method is one which can operate with
  * any of a wide range of call signatures and return types.
- * In order to make this work, both the Java compiler and the JVM must
- * give special treatment to signature polymorphic methods.
  * <p>
  * In source code, a call to a signature polymorphic method will
- * compile, regardless of the requested type descriptor.
+ * compile, regardless of the requested symbolic type descriptor.
  * As usual, the Java compiler emits an {@code invokevirtual}
- * instruction with the given type descriptor against the named method.
- * The unusual part is that the type descriptor is derived from
+ * instruction with the given symbolic type descriptor against the named method.
+ * The unusual part is that the symbolic type descriptor is derived from
  * the actual argument and return types, not from the method declaration.
  * <p>
  * When the JVM processes bytecode containing signature polymorphic calls,
- * it will successfully link any such call, regardless of its type descriptor.
+ * it will successfully link any such call, regardless of its symbolic type descriptor.
  * (In order to retain type safety, the JVM will guard such calls with suitable
  * dynamic type checks, as described elsewhere.)
  * <p>
  * Bytecode generators, including the compiler back end, are required to emit
- * untransformed type descriptors for these methods.
+ * untransformed symbolic type descriptors for these methods.
  * Tools which determine symbolic linkage are required to accept such
  * untransformed descriptors, without reporting linkage errors.
- * <p>
- * For the sake of tools (but not as a programming API), the signature polymorphic
- * methods are marked with a private yet standard annotation,
- * {@code @java.lang.invoke.MethodHandle.PolymorphicSignature}.
- * The annotation's retention is {@code RUNTIME}, so that all tools can see it.
- *
- * <h3>Formal rules for processing signature polymorphic methods</h3>
- * <p>
- * The following methods (and no others) are signature polymorphic:
- * <ul>
- * <li>{@link java.lang.invoke.MethodHandle#invokeExact   MethodHandle.invokeExact}
- * <li>{@link java.lang.invoke.MethodHandle#invoke        MethodHandle.invoke}
- * </ul>
- * <p>
- * A signature polymorphic method will be declared with the following properties:
- * <ul>
- * <li>It must be native.
- * <li>It must take a single varargs parameter of the form {@code Object...}.
- * <li>It must produce a return value of type {@code Object}.
- * <li>It must be contained within the {@code java.lang.invoke} package.
- * </ul>
- * Because of these requirements, a signature polymorphic method is able to accept
- * any number and type of actual arguments, and can, with a cast, produce a value of any type.
- * However, the JVM will treat these declaration features as a documentation convention,
- * rather than a description of the actual structure of the methods as executed.
- * <p>
- * When a call to a signature polymorphic method is compiled, the associated linkage information for
- * its arguments is not array of {@code Object} (as for other similar varargs methods)
- * but rather the erasure of the static types of all the arguments.
- * <p>
- * In an argument position of a method invocation on a signature polymorphic method,
- * a null literal has type {@code java.lang.Void}, unless cast to a reference type.
- * (<em>Note:</em> This typing rule allows the null type to have its own encoding in linkage information
- * distinct from other types.
- * <p>
- * The linkage information for the return type is derived from a context-dependent target typing convention.
- * The return type for a signature polymorphic method invocation is determined as follows:
- * <ul>
- * <li>If the method invocation expression is an expression statement, the method is {@code void}.
- * <li>Otherwise, if the method invocation expression is the immediate operand of a cast,
- * the return type is the erasure of the cast type.
- * <li>Otherwise, the return type is the method's nominal return type, {@code Object}.
- * </ul>
- * (Programmers are encouraged to use explicit casts unless it is clear that a signature polymorphic
- * call will be used as a plain {@code Object} expression.)
- * <p>
- * The linkage information for argument and return types is stored in the descriptor for the
- * compiled (bytecode) call site. As for any invocation instruction, the arguments and return value
- * will be passed directly on the JVM stack, in accordance with the descriptor,
- * and without implicit boxing or unboxing.
  *
  * <h3>Interoperation between method handles and the Core Reflection API</h3>
  * Using factory methods in the {@link java.lang.invoke.MethodHandles.Lookup Lookup} API,
@@ -386,14 +338,14 @@
  * declared method, including in this case {@code native} and {@code varargs} bits.
  * <p>
  * As with any reflected method, these methods (when reflected) may be
- * invoked via {@link java.lang.reflect.Method#invoke Method.invoke}.
+ * invoked via {@link java.lang.reflect.Method#invoke java.lang.reflect.Method.invoke}.
  * However, such reflective calls do not result in method handle invocations.
  * Such a call, if passed the required argument
  * (a single one, of type {@code Object[]}), will ignore the argument and
  * will throw an {@code UnsupportedOperationException}.
  * <p>
  * Since {@code invokevirtual} instructions can natively
- * invoke method handles under any type descriptor, this reflective view conflicts
+ * invoke method handles under any symbolic type descriptor, this reflective view conflicts
  * with the normal presentation of these methods via bytecodes.
  * Thus, these two native methods, when reflectively viewed by
  * {@code Class.getDeclaredMethod}, may be regarded as placeholders only.
@@ -414,7 +366,7 @@
  * When a method handle is invoked, the types of its arguments
  * or the return value cast type may be generic types or type instances.
  * If this occurs, the compiler will replace those
- * types by their erasures when when it constructs the type descriptor
+ * types by their erasures when it constructs the symbolic type descriptor
  * for the {@code invokevirtual} instruction.
  * <p>
  * Method handles do not represent
@@ -503,17 +455,17 @@
 
     /**
      * Invokes the method handle, allowing any caller type descriptor, but requiring an exact type match.
-     * The type descriptor at the call site of {@code invokeExact} must
+     * The symbolic type descriptor at the call site of {@code invokeExact} must
      * exactly match this method handle's {@link #type type}.
      * No conversions are allowed on arguments or return values.
      * <p>
      * When this method is observed via the Core Reflection API,
      * it will appear as a single native method, taking an object array and returning an object.
      * If this native method is invoked directly via
-     * {@link java.lang.reflect.Method#invoke Method.invoke}, via JNI,
+     * {@link java.lang.reflect.Method#invoke java.lang.reflect.Method.invoke}, via JNI,
      * or indirectly via {@link java.lang.invoke.MethodHandles.Lookup#unreflect Lookup.unreflect},
      * it will throw an {@code UnsupportedOperationException}.
-     * @throws WrongMethodTypeException if the target's type is not identical with the caller's type descriptor
+     * @throws WrongMethodTypeException if the target's type is not identical with the caller's symbolic type descriptor
      * @throws Throwable anything thrown by the underlying method propagates unchanged through the method handle call
      */
     public final native @PolymorphicSignature Object invokeExact(Object... args) throws Throwable;
@@ -522,7 +474,7 @@
      * Invokes the method handle, allowing any caller type descriptor,
      * and optionally performing conversions on arguments and return values.
      * <p>
-     * If the call site type descriptor exactly matches this method handle's {@link #type type},
+     * If the call site's symbolic type descriptor exactly matches this method handle's {@link #type type},
      * the call proceeds as if by {@link #invokeExact invokeExact}.
      * <p>
      * Otherwise, the call proceeds as if this method handle were first
@@ -535,7 +487,7 @@
      * adaptations directly on the caller's arguments,
      * and call the target method handle according to its own exact type.
      * <p>
-     * The type descriptor at the call site of {@code invoke} must
+     * The resolved type descriptor at the call site of {@code invoke} must
      * be a valid argument to the receivers {@code asType} method.
      * In particular, the caller must specify the same argument arity
      * as the callee's type,
@@ -544,24 +496,17 @@
      * When this method is observed via the Core Reflection API,
      * it will appear as a single native method, taking an object array and returning an object.
      * If this native method is invoked directly via
-     * {@link java.lang.reflect.Method#invoke Method.invoke}, via JNI,
+     * {@link java.lang.reflect.Method#invoke java.lang.reflect.Method.invoke}, via JNI,
      * or indirectly via {@link java.lang.invoke.MethodHandles.Lookup#unreflect Lookup.unreflect},
      * it will throw an {@code UnsupportedOperationException}.
-     * @throws WrongMethodTypeException if the target's type cannot be adjusted to the caller's type descriptor
+     * @throws WrongMethodTypeException if the target's type cannot be adjusted to the caller's symbolic type descriptor
      * @throws ClassCastException if the target's type can be adjusted to the caller, but a reference cast fails
      * @throws Throwable anything thrown by the underlying method propagates unchanged through the method handle call
      */
     public final native @PolymorphicSignature Object invoke(Object... args) throws Throwable;
 
     /**
-     * <em>Temporary alias</em> for {@link #invoke}, for backward compatibility with some versions of JSR 292.
-     * On some JVMs, support can be excluded by the flags {@code -XX:+UnlockExperimentalVMOptions -XX:-AllowInvokeGeneric}.
-     * @deprecated Will be removed for JSR 292 Proposed Final Draft.
-     */
-    public final native @PolymorphicSignature Object invokeGeneric(Object... args) throws Throwable;
-
-    /**
-     * Performs a varargs invocation, passing the arguments in the given array
+     * Performs a variable arity invocation, passing the arguments in the given array
      * to the method handle, as if via an inexact {@link #invoke invoke} from a call site
      * which mentions only the type {@code Object}, and whose arity is the length
      * of the argument array.
@@ -613,56 +558,16 @@
     public Object invokeWithArguments(Object... arguments) throws Throwable {
         int argc = arguments == null ? 0 : arguments.length;
         MethodType type = type();
-        if (type.parameterCount() != argc) {
+        if (type.parameterCount() != argc || isVarargsCollector()) {
             // simulate invoke
             return asType(MethodType.genericMethodType(argc)).invokeWithArguments(arguments);
         }
-        if (argc <= 10) {
-            MethodHandle invoker = type.invokers().generalInvoker();
-            switch (argc) {
-                case 0:  return invoker.invokeExact(this);
-                case 1:  return invoker.invokeExact(this,
-                                    arguments[0]);
-                case 2:  return invoker.invokeExact(this,
-                                    arguments[0], arguments[1]);
-                case 3:  return invoker.invokeExact(this,
-                                    arguments[0], arguments[1], arguments[2]);
-                case 4:  return invoker.invokeExact(this,
-                                    arguments[0], arguments[1], arguments[2],
-                                    arguments[3]);
-                case 5:  return invoker.invokeExact(this,
-                                    arguments[0], arguments[1], arguments[2],
-                                    arguments[3], arguments[4]);
-                case 6:  return invoker.invokeExact(this,
-                                    arguments[0], arguments[1], arguments[2],
-                                    arguments[3], arguments[4], arguments[5]);
-                case 7:  return invoker.invokeExact(this,
-                                    arguments[0], arguments[1], arguments[2],
-                                    arguments[3], arguments[4], arguments[5],
-                                    arguments[6]);
-                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.invokeExact(this,
-                                    arguments[0], arguments[1], arguments[2],
-                                    arguments[3], arguments[4], arguments[5],
-                                    arguments[6], arguments[7], arguments[8]);
-                case 10:  return invoker.invokeExact(this,
-                                    arguments[0], arguments[1], arguments[2],
-                                    arguments[3], arguments[4], arguments[5],
-                                    arguments[6], arguments[7], arguments[8],
-                                    arguments[9]);
-            }
-        }
-
-        // more than ten arguments get boxed in a varargs list:
-        MethodHandle invoker = type.invokers().spreadInvoker(0);
+        MethodHandle invoker = type.invokers().varargsInvoker();
         return invoker.invokeExact(this, arguments);
     }
 
     /**
-     * Performs a varargs invocation, passing the arguments in the given array
+     * Performs a variable arity invocation, passing the arguments in the given array
      * to the method handle, as if via an inexact {@link #invoke invoke} from a call site
      * which mentions only the type {@code Object}, and whose arity is the length
      * of the argument array.
@@ -674,6 +579,7 @@
      *
      * @param arguments the arguments to pass to the target
      * @return the result returned by the target
+     * @throws NullPointerException if {@code arguments} is a null reference
      * @throws ClassCastException if an argument cannot be converted by reference casting
      * @throws WrongMethodTypeException if the target's type cannot be adjusted to take the given number of {@code Object} arguments
      * @throws Throwable anything thrown by the target method invocation
@@ -690,22 +596,95 @@
      * <p>
      * If the original type and new type are equal, returns {@code this}.
      * <p>
+     * The new method handle, when invoked, will perform the following
+     * steps:
+     * <ul>
+     * <li>Convert the incoming argument list to match the original
+     *     method handle's argument list.
+     * <li>Invoke the original method handle on the converted argument list.
+     * <li>Convert any result returned by the original method handle
+     *     to the return type of new method handle.
+     * </ul>
+     * <p>
      * This method provides the crucial behavioral difference between
-     * {@link #invokeExact invokeExact} and plain, inexact {@link #invoke invoke}.  The two methods
-     * perform the same steps when the caller's type descriptor is identical
-     * with the callee's, but when the types differ, plain {@link #invoke invoke}
+     * {@link #invokeExact invokeExact} and plain, inexact {@link #invoke invoke}.
+     * The two methods
+     * perform the same steps when the caller's type descriptor exactly m atches
+     * the callee's, but when the types differ, plain {@link #invoke invoke}
      * also calls {@code asType} (or some internal equivalent) in order
      * to match up the caller's and callee's types.
      * <p>
-     * This method is equivalent to {@link MethodHandles#convertArguments convertArguments},
-     * except for variable arity method handles produced by {@link #asVarargsCollector asVarargsCollector}.
+     * If the current method is a variable arity method handle
+     * argument list conversion may involve the conversion and collection
+     * of several arguments into an array, as
+     * {@linkplain #asVarargsCollector described elsewhere}.
+     * In every other case, all conversions are applied <em>pairwise</em>,
+     * which means that each argument or return value is converted to
+     * exactly one argument or return value (or no return value).
+     * The applied conversions are defined by consulting the
+     * the corresponding component types of the old and new
+     * method handle types.
+     * <p>
+     * Let <em>T0</em> and <em>T1</em> be corresponding new and old parameter types,
+     * or old and new return types.  Specifically, for some valid index {@code i}, let
+     * <em>T0</em>{@code =newType.parameterType(i)} and <em>T1</em>{@code =this.type().parameterType(i)}.
+     * Or else, going the other way for return values, let
+     * <em>T0</em>{@code =this.type().returnType()} and <em>T1</em>{@code =newType.returnType()}.
+     * If the types are the same, the new method handle makes no change
+     * to the corresponding argument or return value (if any).
+     * Otherwise, one of the following conversions is applied
+     * if possible:
+     * <ul>
+     * <li>If <em>T0</em> and <em>T1</em> are references, then a cast to <em>T1</em> is applied.
+     *     (The types do not need to be related in any particular way.
+     *     This is because a dynamic value of null can convert to any reference type.)
+     * <li>If <em>T0</em> and <em>T1</em> are primitives, then a Java method invocation
+     *     conversion (JLS 5.3) is applied, if one exists.
+     *     (Specifically, <em>T0</em> must convert to <em>T1</em> by a widening primitive conversion.)
+     * <li>If <em>T0</em> is a primitive and <em>T1</em> a reference,
+     *     a Java casting conversion (JLS 5.5) is applied if one exists.
+     *     (Specifically, the value is boxed from <em>T0</em> to its wrapper class,
+     *     which is then widened as needed to <em>T1</em>.)
+     * <li>If <em>T0</em> is a reference and <em>T1</em> a primitive, an unboxing
+     *     conversion will be applied at runtime, possibly followed
+     *     by a Java method invocation conversion (JLS 5.3)
+     *     on the primitive value.  (These are the primitive widening conversions.)
+     *     <em>T0</em> must be a wrapper class or a supertype of one.
+     *     (In the case where <em>T0</em> is Object, these are the conversions
+     *     allowed by {@link java.lang.reflect.Method#invoke java.lang.reflect.Method.invoke}.)
+     *     The unboxing conversion must have a possibility of success, which means that
+     *     if <em>T0</em> is not itself a wrapper class, there must exist at least one
+     *     wrapper class <em>TW</em> which is a subtype of <em>T0</em> and whose unboxed
+     *     primitive value can be widened to <em>T1</em>.
+     * <li>If the return type <em>T1</em> is marked as void, any returned value is discarded
+     * <li>If the return type <em>T0</em> is void and <em>T1</em> a reference, a null value is introduced.
+     * <li>If the return type <em>T0</em> is void and <em>T1</em> a primitive,
+     *     a zero value is introduced.
+     * </ul>
+    * (<em>Note:</em> Both <em>T0</em> and <em>T1</em> may be regarded as static types,
+     * because neither corresponds specifically to the <em>dynamic type</em> of any
+     * actual argument or return value.)
+     * <p>
+     * The method handle conversion cannot be made if any one of the required
+     * pairwise conversions cannot be made.
+     * <p>
+     * At runtime, the conversions applied to reference arguments
+     * or return values may require additional runtime checks which can fail.
+     * An unboxing operation may fail because the original reference is null,
+     * causing a {@link java.lang.NullPointerException NullPointerException}.
+     * An unboxing operation or a reference cast may also fail on a reference
+     * to an object of the wrong type,
+     * causing a {@link java.lang.ClassCastException ClassCastException}.
+     * Although an unboxing operation may accept several kinds of wrappers,
+     * if none are available, a {@code ClassCastException} will be thrown.
      *
      * @param newType the expected type of the new method handle
      * @return a method handle which delegates to {@code this} after performing
      *           any necessary argument conversions, and arranges for any
      *           necessary return value conversions
+     * @throws NullPointerException if {@code newType} is a null reference
      * @throws WrongMethodTypeException if the conversion cannot be made
-     * @see MethodHandles#convertArguments
+     * @see MethodHandles#explicitCastArguments
      */
     public MethodHandle asType(MethodType newType) {
         if (!type.isConvertibleTo(newType)) {
@@ -715,7 +694,7 @@
     }
 
     /**
-     * Makes an adapter which accepts a trailing array argument
+     * Makes an <em>array-spreading</em> method handle, which accepts a trailing array argument
      * and spreads its elements as positional arguments.
      * The new method handle adapts, as its <i>target</i>,
      * the current method handle.  The type of the adapter will be
@@ -740,13 +719,54 @@
      * contains exactly enough elements to provide a correct argument count
      * to the target method handle.
      * (The array may also be null when zero elements are required.)
+     * <p>
+     * Here are some simple examples of array-spreading method handles:
+     * <blockquote><pre>
+MethodHandle equals = publicLookup()
+  .findVirtual(String.class, "equals", methodType(boolean.class, Object.class));
+assert( (boolean) equals.invokeExact("me", (Object)"me"));
+assert(!(boolean) equals.invokeExact("me", (Object)"thee"));
+// spread both arguments from a 2-array:
+MethodHandle eq2 = equals.asSpreader(Object[].class, 2);
+assert( (boolean) eq2.invokeExact(new Object[]{ "me", "me" }));
+assert(!(boolean) eq2.invokeExact(new Object[]{ "me", "thee" }));
+// spread both arguments from a String array:
+MethodHandle eq2s = equals.asSpreader(String[].class, 2);
+assert( (boolean) eq2s.invokeExact(new String[]{ "me", "me" }));
+assert(!(boolean) eq2s.invokeExact(new String[]{ "me", "thee" }));
+// spread second arguments from a 1-array:
+MethodHandle eq1 = equals.asSpreader(Object[].class, 1);
+assert( (boolean) eq1.invokeExact("me", new Object[]{ "me" }));
+assert(!(boolean) eq1.invokeExact("me", new Object[]{ "thee" }));
+// spread no arguments from a 0-array or null:
+MethodHandle eq0 = equals.asSpreader(Object[].class, 0);
+assert( (boolean) eq0.invokeExact("me", (Object)"me", new Object[0]));
+assert(!(boolean) eq0.invokeExact("me", (Object)"thee", (Object[])null));
+// asSpreader and asCollector are approximate inverses:
+for (int n = 0; n <= 2; n++) {
+    for (Class<?> a : new Class<?>[]{Object[].class, String[].class, CharSequence[].class}) {
+        MethodHandle equals2 = equals.asSpreader(a, n).asCollector(a, n);
+        assert( (boolean) equals2.invokeWithArguments("me", "me"));
+        assert(!(boolean) equals2.invokeWithArguments("me", "thee"));
+    }
+}
+MethodHandle caToString = publicLookup()
+  .findStatic(Arrays.class, "toString", methodType(String.class, char[].class));
+assertEquals("[A, B, C]", (String) caToString.invokeExact("ABC".toCharArray()));
+MethodHandle caString3 = caToString.asCollector(char[].class, 3);
+assertEquals("[A, B, C]", (String) caString3.invokeExact('A', 'B', 'C'));
+MethodHandle caToString2 = caString3.asSpreader(char[].class, 2);
+assertEquals("[A, B, C]", (String) caToString2.invokeExact('A', "BC".toCharArray()));
+     * </pre></blockquote>
      * @param arrayType usually {@code Object[]}, the type of the array argument from which to extract the spread arguments
      * @param arrayLength the number of arguments to spread from an incoming array argument
      * @return a new method handle which spreads its final array argument,
      *         before calling the original method handle
+     * @throws NullPointerException if {@code arrayType} is a null reference
      * @throws IllegalArgumentException if {@code arrayType} is not an array type
      * @throws IllegalArgumentException if target does not have at least
-     *         {@code arrayLength} parameter types
+     *         {@code arrayLength} parameter types,
+     *         or if {@code arrayLength} is negative
      * @throws WrongMethodTypeException if the implied {@code asType} call fails
      * @see #asCollector
      */
@@ -758,7 +778,8 @@
     private void asSpreaderChecks(Class<?> arrayType, int arrayLength) {
         spreadArrayChecks(arrayType, arrayLength);
         int nargs = type().parameterCount();
-        if (nargs < arrayLength)  throw newIllegalArgumentException("bad spread array length");
+        if (nargs < arrayLength || arrayLength < 0)
+            throw newIllegalArgumentException("bad spread array length");
         if (arrayType != Object[].class && arrayLength != 0) {
             boolean sawProblem = false;
             Class<?> arrayElement = arrayType.getComponentType();
@@ -794,7 +815,7 @@
     }
 
     /**
-     * Makes an adapter which accepts a given number of trailing
+     * Makes an <em>array-collecting</em> method handle, which accepts a given number of trailing
      * positional arguments and collects them into an array argument.
      * The new method handle adapts, as its <i>target</i>,
      * the current method handle.  The type of the adapter will be
@@ -821,10 +842,40 @@
      * <p>
      * In order to create a collecting adapter which is not restricted to a particular
      * number of collected arguments, use {@link #asVarargsCollector asVarargsCollector} instead.
+     * <p>
+     * Here are some examples of array-collecting method handles:
+     * <blockquote><pre>
+MethodHandle deepToString = publicLookup()
+  .findStatic(Arrays.class, "deepToString", methodType(String.class, Object[].class));
+assertEquals("[won]",   (String) deepToString.invokeExact(new Object[]{"won"}));
+MethodHandle ts1 = deepToString.asCollector(Object[].class, 1);
+assertEquals(methodType(String.class, Object.class), ts1.type());
+//assertEquals("[won]", (String) ts1.invokeExact(         new Object[]{"won"})); //FAIL
+assertEquals("[[won]]", (String) ts1.invokeExact((Object) new Object[]{"won"}));
+// arrayType can be a subtype of Object[]
+MethodHandle ts2 = deepToString.asCollector(String[].class, 2);
+assertEquals(methodType(String.class, String.class, String.class), ts2.type());
+assertEquals("[two, too]", (String) ts2.invokeExact("two", "too"));
+MethodHandle ts0 = deepToString.asCollector(Object[].class, 0);
+assertEquals("[]", (String) ts0.invokeExact());
+// collectors can be nested, Lisp-style
+MethodHandle ts22 = deepToString.asCollector(Object[].class, 3).asCollector(String[].class, 2);
+assertEquals("[A, B, [C, D]]", ((String) ts22.invokeExact((Object)'A', (Object)"B", "C", "D")));
+// arrayType can be any primitive array type
+MethodHandle bytesToString = publicLookup()
+  .findStatic(Arrays.class, "toString", methodType(String.class, byte[].class))
+  .asCollector(byte[].class, 3);
+assertEquals("[1, 2, 3]", (String) bytesToString.invokeExact((byte)1, (byte)2, (byte)3));
+MethodHandle longsToString = publicLookup()
+  .findStatic(Arrays.class, "toString", methodType(String.class, long[].class))
+  .asCollector(long[].class, 1);
+assertEquals("[123]", (String) longsToString.invokeExact((long)123));
+     * </pre></blockquote>
      * @param arrayType often {@code Object[]}, the type of the array argument which will collect the arguments
      * @param arrayLength the number of arguments to collect into a new array argument
      * @return a new method handle which collects some trailing argument
      *         into an array, before calling the original method handle
+     * @throws NullPointerException if {@code arrayType} is a null reference
      * @throws IllegalArgumentException if {@code arrayType} is not an array type
      *         or {@code arrayType} is not assignable to this method handle's trailing parameter type,
      *         or {@code arrayLength} is not a legal array size
@@ -838,11 +889,16 @@
         return MethodHandleImpl.collectArguments(this, type.parameterCount()-1, collector);
     }
 
-    private void asCollectorChecks(Class<?> arrayType, int arrayLength) {
+    // private API: return true if last param exactly matches arrayType
+    private boolean asCollectorChecks(Class<?> arrayType, int arrayLength) {
         spreadArrayChecks(arrayType, arrayLength);
         int nargs = type().parameterCount();
-        if (nargs == 0 || !type().parameterType(nargs-1).isAssignableFrom(arrayType))
-            throw newIllegalArgumentException("array type not assignable to trailing argument", this, arrayType);
+        if (nargs != 0) {
+            Class<?> lastParam = type().parameterType(nargs-1);
+            if (lastParam == arrayType)  return true;
+            if (lastParam.isAssignableFrom(arrayType))  return false;
+        }
+        throw newIllegalArgumentException("array type not assignable to trailing argument", this, arrayType);
     }
 
     /**
@@ -859,6 +915,10 @@
      * {@code arrayType}, even if the target has a different
      * last parameter type.
      * <p>
+     * This transformation may return {@code this} if the method handle is
+     * already of variable arity and its trailing parameter type
+     * is identical to {@code arrayType}.
+     * <p>
      * When called with {@link #invokeExact invokeExact}, the adapter invokes
      * the target with no argument changes.
      * (<em>Note:</em> This behavior is different from a
@@ -875,8 +935,8 @@
      * trailing parameter type of the caller is a reference type identical to
      * or assignable to the trailing parameter type of the adapter,
      * the arguments and return values are converted pairwise,
-     * as if by {@link MethodHandles#convertArguments convertArguments}.
-     * (This is also normal behavior for {@code invoke} in such a case.)
+     * as if by {@link #asType asType} on a fixed arity
+     * method handle.
      * <p>
      * Otherwise, the arities differ, or the adapter's trailing parameter
      * type is not assignable from the corresponding caller type.
@@ -944,14 +1004,24 @@
      * <p>
      * Here is an example, of a list-making variable arity method handle:
      * <blockquote><pre>
+MethodHandle deepToString = publicLookup()
+  .findStatic(Arrays.class, "deepToString", methodType(String.class, Object[].class));
+MethodHandle ts1 = deepToString.asVarargsCollector(Object[].class);
+assertEquals("[won]",   (String) ts1.invokeExact(    new Object[]{"won"}));
+assertEquals("[won]",   (String) ts1.invoke(         new Object[]{"won"}));
+assertEquals("[won]",   (String) ts1.invoke(                      "won" ));
+assertEquals("[[won]]", (String) ts1.invoke((Object) new Object[]{"won"}));
+// findStatic of Arrays.asList(...) produces a variable arity method handle:
 MethodHandle asList = publicLookup()
-  .findStatic(Arrays.class, "asList", methodType(List.class, Object[].class))
-  .asVarargsCollector(Object[].class);
+  .findStatic(Arrays.class, "asList", methodType(List.class, Object[].class));
+assertEquals(methodType(List.class, Object[].class), asList.type());
+assert(asList.isVarargsCollector());
 assertEquals("[]", asList.invoke().toString());
 assertEquals("[1]", asList.invoke(1).toString());
 assertEquals("[two, too]", asList.invoke("two", "too").toString());
-Object[] argv = { "three", "thee", "tee" };
+String[] argv = { "three", "thee", "tee" };
 assertEquals("[three, thee, tee]", asList.invoke(argv).toString());
+assertEquals("[three, thee, tee]", asList.invoke((Object[])argv).toString());
 List ls = (List) asList.invoke((Object)argv);
 assertEquals(1, ls.size());
 assertEquals("[three, thee, tee]", Arrays.toString((Object[])ls.get(0)));
@@ -968,38 +1038,24 @@
      * or not a single trailing argument is interpreted as a whole
      * array or a single element of an array to be collected.
      * Note that the dynamic type of the trailing argument has no
-     * effect on this decision, only a comparison between the static
-     * type descriptor of the call site and the type of the method handle.)
-     * <p style="font-size:smaller;">
-     * As a result of the previously stated rules, the variable arity behavior
-     * of a method handle may be suppressed, by binding it to the exact invoker
-     * of its own type, as follows:
-     * <blockquote><pre>
-MethodHandle vamh = publicLookup()
-  .findStatic(Arrays.class, "asList", methodType(List.class, Object[].class))
-  .asVarargsCollector(Object[].class);
-MethodHandle mh = MethodHandles.exactInvoker(vamh.type()).bindTo(vamh);
-assert(vamh.type().equals(mh.type()));
-assertEquals("[1, 2, 3]", vamh.invoke(1,2,3).toString());
-boolean failed = false;
-try { mh.invoke(1,2,3); }
-catch (WrongMethodTypeException ex) { failed = true; }
-assert(failed);
-     * </pre></blockquote>
-     * This transformation has no behavioral effect if the method handle is
-     * not of variable arity.
+     * effect on this decision, only a comparison between the symbolic
+     * type descriptor of the call site and the type descriptor of the method handle.)
      *
      * @param arrayType often {@code Object[]}, the type of the array argument which will collect the arguments
      * @return a new method handle which can collect any number of trailing arguments
      *         into an array, before calling the original method handle
+     * @throws NullPointerException if {@code arrayType} is a null reference
      * @throws IllegalArgumentException if {@code arrayType} is not an array type
      *         or {@code arrayType} is not assignable to this method handle's trailing parameter type
      * @see #asCollector
      * @see #isVarargsCollector
+     * @see #asFixedArity
      */
     public MethodHandle asVarargsCollector(Class<?> arrayType) {
         Class<?> arrayElement = arrayType.getComponentType();
-        asCollectorChecks(arrayType, 0);
+        boolean lastMatch = asCollectorChecks(arrayType, 0);
+        if (isVarargsCollector() && lastMatch)
+            return this;
         return AdapterMethodHandle.makeVarargsCollector(this, arrayType);
     }
 
@@ -1016,12 +1072,61 @@
      * </ul>
      * @return true if this method handle accepts more than one arity of plain, inexact {@code invoke} calls
      * @see #asVarargsCollector
+     * @see #asFixedArity
      */
     public boolean isVarargsCollector() {
         return false;
     }
 
     /**
+     * Makes a <em>fixed arity</em> method handle which is otherwise
+     * equivalent to the the current method handle.
+     * <p>
+     * If the current method handle is not of
+     * {@linkplain #asVarargsCollector variable arity},
+     * the current method handle is returned.
+     * This is true even if the current method handle
+     * could not be a valid input to {@code asVarargsCollector}.
+     * <p>
+     * Otherwise, the resulting fixed-arity method handle has the same
+     * type and behavior of the current method handle,
+     * except that {@link #isVarargsCollector isVarargsCollector}
+     * will be false.
+     * The fixed-arity method handle may (or may not) be the
+     * a previous argument to {@code asVarargsCollector}.
+     * <p>
+     * Here is an example, of a list-making variable arity method handle:
+     * <blockquote><pre>
+MethodHandle asListVar = publicLookup()
+  .findStatic(Arrays.class, "asList", methodType(List.class, Object[].class))
+  .asVarargsCollector(Object[].class);
+MethodHandle asListFix = asListVar.asFixedArity();
+assertEquals("[1]", asListVar.invoke(1).toString());
+Exception caught = null;
+try { asListFix.invoke((Object)1); }
+catch (Exception ex) { caught = ex; }
+assert(caught instanceof ClassCastException);
+assertEquals("[two, too]", asListVar.invoke("two", "too").toString());
+try { asListFix.invoke("two", "too"); }
+catch (Exception ex) { caught = ex; }
+assert(caught instanceof WrongMethodTypeException);
+Object[] argv = { "three", "thee", "tee" };
+assertEquals("[three, thee, tee]", asListVar.invoke(argv).toString());
+assertEquals("[three, thee, tee]", asListFix.invoke(argv).toString());
+assertEquals(1, ((List) asListVar.invoke((Object)argv)).size());
+assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString());
+     * </pre></blockquote>
+     *
+     * @return a new method handle which accepts only a fixed number of arguments
+     * @see #asVarargsCollector
+     * @see #isVarargsCollector
+     */
+    public MethodHandle asFixedArity() {
+        assert(!isVarargsCollector());
+        return this;
+    }
+
+    /**
      * Binds a value {@code x} to the first argument of a method handle, without invoking it.
      * The new method handle adapts, as its <i>target</i>,
      * the current method handle by binding it to the given argument.
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java	Thu May 26 20:20:03 2011 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java	Fri May 27 19:03:03 2011 -0700
@@ -82,12 +82,17 @@
         }
         DirectMethodHandle mh = new DirectMethodHandle(mtype, method, doDispatch, lookupClass);
         if (!mh.isValid())
-            throw method.makeAccessException("no access", lookupClass);
+            throw method.makeAccessException("no direct method handle", lookupClass);
         assert(mh.type() == mtype);
         if (!method.isVarargs())
             return mh;
-        else
-            return mh.asVarargsCollector(mtype.parameterType(mtype.parameterCount()-1));
+        int argc = mtype.parameterCount();
+        if (argc != 0) {
+            Class<?> arrayType = mtype.parameterType(argc-1);
+            if (arrayType.isArray())
+                return AdapterMethodHandle.makeVarargsCollector(mh, arrayType);
+        }
+        throw method.makeAccessException("cannot make variable arity", null);
     }
 
     static
@@ -485,14 +490,14 @@
      */
     static
     MethodHandle bindReceiver(MethodHandle target, Object receiver) {
+        if (receiver == null)  return null;
         if (target instanceof AdapterMethodHandle &&
             ((AdapterMethodHandle)target).conversionOp() == MethodHandleNatives.Constants.OP_RETYPE_ONLY
             ) {
             Object info = MethodHandleNatives.getTargetInfo(target);
             if (info instanceof DirectMethodHandle) {
                 DirectMethodHandle dmh = (DirectMethodHandle) info;
-                if (receiver == null ||
-                    dmh.type().parameterType(0).isAssignableFrom(receiver.getClass())) {
+                if (dmh.type().parameterType(0).isAssignableFrom(receiver.getClass())) {
                     MethodHandle bmh = new BoundMethodHandle(dmh, receiver, 0);
                     MethodType newType = target.type().dropParameterTypes(0, 1);
                     return convertArguments(bmh, newType, bmh.type(), 0);
@@ -698,7 +703,9 @@
             if (target == null)  throw newIllegalArgumentException("cannot drop");
             oldType = target.type();
         }
-        return convertArguments(target, newType, oldType, 0);
+        target = convertArguments(target, newType, oldType, 0);
+        assert(target != null);
+        return target;
     }
 
     /*non-public*/ static
@@ -907,14 +914,16 @@
             this.test = test;
             this.target = target;
             this.fallback = fallback;
-            assert(MethodHandleNatives.workaroundWithoutRicochetFrames());  // this code is deprecated
         }
-        // FIXME: Build the control flow out of foldArguments.
+        static boolean preferRicochetFrame(MethodType type) {
+            return (type.parameterCount() >= INVOKES.length || type.hasPrimitives());
+        }
         static MethodHandle make(MethodHandle test, MethodHandle target, MethodHandle fallback) {
-            assert(MethodHandleNatives.workaroundWithoutRicochetFrames());  // this code is deprecated
             MethodType type = target.type();
             int nargs = type.parameterCount();
             if (nargs < INVOKES.length) {
+                if (preferRicochetFrame(type))
+                    assert(MethodHandleNatives.workaroundWithoutRicochetFrames());  // this code is deprecated
                 MethodHandle invoke = INVOKES[nargs];
                 MethodType gtype = type.generic();
                 assert(invoke.type().dropParameterTypes(0,1) == gtype);
@@ -925,6 +934,7 @@
                 MethodHandle gguard = new GuardWithTest(invoke, gtest, gtarget, gfallback);
                 return convertArguments(gguard, type, gtype, 0);
             } else {
+                assert(MethodHandleNatives.workaroundWithoutRicochetFrames());  // this code is deprecated
                 MethodHandle invoke = VARARGS_INVOKE;
                 MethodType gtype = MethodType.genericMethodType(1);
                 assert(invoke.type().dropParameterTypes(0,1) == gtype);
@@ -1048,8 +1058,10 @@
         //    where select(z) = select(z, t, f).bindTo(t, f) => z ? t f
         // [tailcall]=> tf(arg...)
         assert(test.type().returnType() == boolean.class);
-        MethodType foldTargetType = target.type().insertParameterTypes(0, boolean.class);
-        if (AdapterMethodHandle.canCollectArguments(foldTargetType, test.type(), 0, true)) {
+        MethodType targetType = target.type();
+        MethodType foldTargetType = targetType.insertParameterTypes(0, boolean.class);
+        if (AdapterMethodHandle.canCollectArguments(foldTargetType, test.type(), 0, true)
+            && GuardWithTest.preferRicochetFrame(targetType)) {
             // working backwards, as usual:
             assert(target.type().equals(fallback.type()));
             MethodHandle tailcall = MethodHandles.exactInvoker(target.type());
@@ -1062,7 +1074,6 @@
             MethodHandle fold = foldArguments(filter, filter.type().dropParameterTypes(0, 1), 0, test);
             return fold;
         }
-        assert(MethodHandleNatives.workaroundWithoutRicochetFrames());  // this code is deprecated
         return GuardWithTest.make(test, target, fallback);
     }
 
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java	Thu May 26 20:20:03 2011 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java	Fri May 27 19:03:03 2011 -0700
@@ -400,7 +400,7 @@
             case REF_newInvokeSpecial:  return lookup.findConstructor(  defc,       (MethodType) type );
             case REF_invokeInterface:   return lookup.findVirtual(      defc, name, (MethodType) type );
             }
-            throw new IllegalArgumentException("bad MethodHandle constant "+name+" : "+type);
+            throw new InternalError("bad MethodHandle constant "+name+" : "+type);
         } catch (ReflectiveOperationException ex) {
             Error err = new IncompatibleClassChangeError();
             err.initCause(ex);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleProxies.java	Fri May 27 19:03:03 2011 -0700
@@ -0,0 +1,257 @@
+/*
+ * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.invoke;
+
+import java.lang.reflect.*;
+import sun.invoke.WrapperInstance;
+
+/**
+ * This class consists exclusively of static methods that help adapt
+ * method handles to other JVM types, such as interfaces.
+ */
+public class MethodHandleProxies {
+
+    private MethodHandleProxies() { }  // do not instantiate
+
+    /**
+     * Produces an instance of the given single-method interface which redirects
+     * its calls to the given method handle.
+     * <p>
+     * A single-method interface is an interface which declares a uniquely named method.
+     * When determining the uniquely named method of a single-method interface,
+     * the public {@code Object} methods ({@code toString}, {@code equals}, {@code hashCode})
+     * are disregarded.  For example, {@link java.util.Comparator} is a single-method interface,
+     * even though it re-declares the {@code Object.equals} method.
+     * <p>
+     * The interface must be public.  No additional access checks are performed.
+     * <p>
+     * The resulting instance of the required type will respond to
+     * invocation of the type's uniquely named method by calling
+     * the given target on the incoming arguments,
+     * and returning or throwing whatever the target
+     * returns or throws.  The invocation will be as if by
+     * {@code target.invoke}.
+     * The target's type will be checked before the
+     * instance is created, as if by a call to {@code asType},
+     * which may result in a {@code WrongMethodTypeException}.
+     * <p>
+     * The uniquely named method is allowed to be multiply declared,
+     * with distinct type descriptors.  (E.g., it can be overloaded,
+     * or can possess bridge methods.)  All such declarations are
+     * connected directly to the target method handle.
+     * Argument and return types are adjusted by {@code asType}
+     * for each individual declaration.
+     * <p>
+     * The wrapper instance will implement the requested interface
+     * and its super-types, but no other single-method interfaces.
+     * This means that the instance will not unexpectedly
+     * pass an {@code instanceof} test for any unrequested type.
+     * <p style="font-size:smaller;">
+     * <em>Implementation Note:</em>
+     * Therefore, each instance must implement a unique single-method interface.
+     * Implementations may not bundle together
+     * multiple single-method interfaces onto single implementation classes
+     * in the style of {@link java.awt.AWTEventMulticaster}.
+     * <p>
+     * The method handle may throw an <em>undeclared exception</em>,
+     * which means any checked exception (or other checked throwable)
+     * not declared by the requested type's single abstract method.
+     * If this happens, the throwable will be wrapped in an instance of
+     * {@link java.lang.reflect.UndeclaredThrowableException UndeclaredThrowableException}
+     * and thrown in that wrapped form.
+     * <p>
+     * Like {@link java.lang.Integer#valueOf Integer.valueOf},
+     * {@code asInterfaceInstance} is a factory method whose results are defined
+     * by their behavior.
+     * It is not guaranteed to return a new instance for every call.
+     * <p>
+     * Because of the possibility of {@linkplain java.lang.reflect.Method#isBridge bridge methods}
+     * and other corner cases, the interface may also have several abstract methods
+     * with the same name but having distinct descriptors (types of returns and parameters).
+     * In this case, all the methods are bound in common to the one given target.
+     * The type check and effective {@code asType} conversion is applied to each
+     * method type descriptor, and all abstract methods are bound to the target in common.
+     * Beyond this type check, no further checks are made to determine that the
+     * abstract methods are related in any way.
+     * <p>
+     * Future versions of this API may accept additional types,
+     * such as abstract classes with single abstract methods.
+     * Future versions of this API may also equip wrapper instances
+     * with one or more additional public "marker" interfaces.
+     *
+     * @param target the method handle to invoke from the wrapper
+     * @param intfc the desired type of the wrapper, a single-method interface
+     * @return a correctly-typed wrapper for the given target
+     * @throws NullPointerException if either argument is null
+     * @throws IllegalArgumentException if the {@code intfc} is not a
+     *         valid argument to this method
+     * @throws WrongMethodTypeException if the target cannot
+     *         be converted to the type required by the requested interface
+     */
+    // Other notes to implementors:
+    // <p>
+    // No stable mapping is promised between the single-method interface and
+    // the implementation class C.  Over time, several implementation
+    // classes might be used for the same type.
+    // <p>
+    // If the implementation is able
+    // to prove that a wrapper of the required type
+    // has already been created for a given
+    // method handle, or for another method handle with the
+    // same behavior, the implementation may return that wrapper in place of
+    // a new wrapper.
+    // <p>
+    // This method is designed to apply to common use cases
+    // where a single method handle must interoperate with
+    // an interface that implements a function-like
+    // API.  Additional variations, such as single-abstract-method classes with
+    // private constructors, or interfaces with multiple but related
+    // entry points, must be covered by hand-written or automatically
+    // generated adapter classes.
+    //
+    public static
+    <T> T asInterfaceInstance(final Class<T> intfc, final MethodHandle target) {
+        // POC implementation only; violates the above contract several ways
+        final Method sm = getSingleMethod(intfc);
+        if (sm == null)
+            throw new IllegalArgumentException("not a single-method interface: "+intfc.getName());
+        MethodType smMT = MethodType.methodType(sm.getReturnType(), sm.getParameterTypes());
+        MethodHandle checkTarget = target.asType(smMT);  // make throw WMT
+        checkTarget = checkTarget.asType(checkTarget.type().changeReturnType(Object.class));
+        final MethodHandle vaTarget = checkTarget.asSpreader(Object[].class, smMT.parameterCount());
+        return intfc.cast(Proxy.newProxyInstance(
+                intfc.getClassLoader(),
+                new Class[]{ intfc, WrapperInstance.class },
+                new InvocationHandler() {
+                    private Object getArg(String name) {
+                        if ((Object)name == "getWrapperInstanceTarget")  return target;
+                        if ((Object)name == "getWrapperInstanceType")    return intfc;
+                        throw new AssertionError();
+                    }
+                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+                        if (method.getDeclaringClass() == WrapperInstance.class)
+                            return getArg(method.getName());
+                        if (method.equals(sm))
+                            return vaTarget.invokeExact(args);
+                        if (isObjectMethod(method))
+                            return callObjectMethod(this, method, args);
+                        throw new InternalError();
+                    }
+                }));
+    }
+
+    /**
+     * Determines if the given object was produced by a call to {@link #asInterfaceInstance asInterfaceInstance}.
+     * @param x any reference
+     * @return true if the reference is not null and points to an object produced by {@code asInterfaceInstance}
+     */
+    public static
+    boolean isWrapperInstance(Object x) {
+        return x instanceof WrapperInstance;
+    }
+
+    private static WrapperInstance asWrapperInstance(Object x) {
+        try {
+            if (x != null)
+                return (WrapperInstance) x;
+        } catch (ClassCastException ex) {
+        }
+        throw new IllegalArgumentException("not a wrapper instance");
+    }
+
+    /**
+     * Produces or recovers a target method handle which is behaviorally
+     * equivalent to the unique method of this wrapper instance.
+     * The object {@code x} must have been produced by a call to {@link #asInterfaceInstance asInterfaceInstance}.
+     * This requirement may be tested via {@link #isWrapperInstance isWrapperInstance}.
+     * @param x any reference
+     * @return a method handle implementing the unique method
+     * @throws IllegalArgumentException if the reference x is not to a wrapper instance
+     */
+    public static
+    MethodHandle wrapperInstanceTarget(Object x) {
+        return asWrapperInstance(x).getWrapperInstanceTarget();
+    }
+
+    /**
+     * Recovers the unique single-method interface type for which this wrapper instance was created.
+     * The object {@code x} must have been produced by a call to {@link #asInterfaceInstance asInterfaceInstance}.
+     * This requirement may be tested via {@link #isWrapperInstance isWrapperInstance}.
+     * @param x any reference
+     * @return the single-method interface type for which the wrapper was created
+     * @throws IllegalArgumentException if the reference x is not to a wrapper instance
+     */
+    public static
+    Class<?> wrapperInstanceType(Object x) {
+        return asWrapperInstance(x).getWrapperInstanceType();
+    }
+
+    private static
+    boolean isObjectMethod(Method m) {
+        switch (m.getName()) {
+        case "toString":
+            return (m.getReturnType() == String.class
+                    && m.getParameterTypes().length == 0);
+        case "hashCode":
+            return (m.getReturnType() == int.class
+                    && m.getParameterTypes().length == 0);
+        case "equals":
+            return (m.getReturnType() == boolean.class
+                    && m.getParameterTypes().length == 1
+                    && m.getParameterTypes()[0] == Object.class);
+        }
+        return false;
+    }
+
+    private static
+    Object callObjectMethod(Object self, Method m, Object[] args) {
+        assert(isObjectMethod(m)) : m;
+        switch (m.getName()) {
+        case "toString":
+            return self.getClass().getName() + "@" + Integer.toHexString(self.hashCode());
+        case "hashCode":
+            return System.identityHashCode(self);
+        case "equals":
+            return (self == args[0]);
+        }
+        return null;
+    }
+
+    private static
+    Method getSingleMethod(Class<?> intfc) {
+        if (!intfc.isInterface())  return null;
+        Method sm = null;
+        for (Method m : intfc.getMethods()) {
+            int mod = m.getModifiers();
+            if (Modifier.isAbstract(mod)) {
+                if (sm != null && !isObjectMethod(sm))
+                    return null;  // too many abstract methods
+                sm = m;
+            }
+        }
+        return sm;
+    }
+}
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandles.java	Thu May 26 20:20:03 2011 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandles.java	Fri May 27 19:03:03 2011 -0700
@@ -180,6 +180,10 @@
      * The names {@code aMethod}, {@code aField}, and {@code aConstructor} stand
      * for reflective objects corresponding to the given members.
      * <p>
+     * In cases where the given member is of variable arity (i.e., a method or constructor)
+     * the returned method handle will also be of {@linkplain MethodHandle#asVarargsCollector variable arity}.
+     * In all other cases, the returned method handle will be of fixed arity.
+     * <p>
      * The equivalence between looked-up method handles and underlying
      * class members can break down in a few ways:
      * <ul>
@@ -201,7 +205,7 @@
      * Access checks are applied in the factory methods of {@code Lookup},
      * when a method handle is created.
      * This is a key difference from the Core Reflection API, since
-     * {@link java.lang.reflect.Method#invoke Method.invoke}
+     * {@link java.lang.reflect.Method#invoke java.lang.reflect.Method.invoke}
      * performs access checking against every caller, on every call.
      * <p>
      * All access checks start from a {@code Lookup} object, which
@@ -267,7 +271,7 @@
      * Access checks only apply to named and reflected methods,
      * constructors, and fields.
      * Other method handle creation methods, such as
-     * {@link #convertArguments MethodHandles.convertArguments},
+     * {@link MethodHandle#asType MethodHandle.asType},
      * do not require any access checks, and are done
      * with static methods of {@link MethodHandles},
      * independently of any {@code Lookup} object.
@@ -296,6 +300,12 @@
      *     {@link SecurityManager#checkMemberAccess
      *     smgr.checkMemberAccess(defc, Member.DECLARED)} is called.
      *     (Note that {@code defc} might be the same as {@code refc}.)
+     *     The default implementation of this security manager method
+     *     inspects the stack to determine the original caller of
+     *     the reflective request (such as {@code findStatic}),
+     *     and performs additional permission checks if the
+     *     class loader of {@code defc} differs from the class
+     *     loader of the class from which the reflective request came.
      * <li>If the retrieved member is not public,
      *     and if {@code defc} and {@code refc} are in different class loaders,
      *     and if the class loader of the lookup class is not
@@ -304,8 +314,6 @@
      *     smgr.checkPackageAccess(defcPkg)} is called,
      *     where {@code defcPkg} is the package of {@code defc}.
      * </ul>
-     * In all cases, the requesting class presented to the security
-     * manager will be the lookup class from the current {@code Lookup} object.
      */
     public static final
     class Lookup {
@@ -559,7 +567,10 @@
          * @param type the type of the method
          * @return the desired method handle
          * @throws NoSuchMethodException if the method does not exist
-         * @throws IllegalAccessException if access checking fails, or if the method is not {@code static}
+         * @throws IllegalAccessException if access checking fails,
+         *                                or if the method is not {@code static},
+         *                                or if the method's variable arity modifier bit
+         *                                is set and {@code asVarargsCollector} fails
          * @exception SecurityException if a security manager is present and it
          *                              <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
          * @throws NullPointerException if any argument is null
@@ -567,6 +578,7 @@
         public
         MethodHandle findStatic(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
             MemberName method = resolveOrFail(refc, name, type, true);
+            checkSecurityManager(refc, method);  // stack walk magic: do not refactor
             checkMethod(refc, method, true);
             return MethodHandleImpl.findMethod(method, false, lookupClassOrNull());
         }
@@ -601,13 +613,17 @@
          * @param type the type of the method, with the receiver argument omitted
          * @return the desired method handle
          * @throws NoSuchMethodException if the method does not exist
-         * @throws IllegalAccessException if access checking fails, or if the method is {@code static}
+         * @throws IllegalAccessException if access checking fails,
+         *                                or if the method is {@code static}
+         *                                or if the method's variable arity modifier bit
+         *                                is set and {@code asVarargsCollector} fails
          * @exception SecurityException if a security manager is present and it
          *                              <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
          * @throws NullPointerException if any argument is null
          */
         public MethodHandle findVirtual(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
             MemberName method = resolveOrFail(refc, name, type, false);
+            checkSecurityManager(refc, method);  // stack walk magic: do not refactor
             checkMethod(refc, method, false);
             MethodHandle mh = MethodHandleImpl.findMethod(method, true, lookupClassOrNull());
             return restrictProtectedReceiver(method, mh);
@@ -633,6 +649,8 @@
          * @return the desired method handle
          * @throws NoSuchMethodException if the constructor does not exist
          * @throws IllegalAccessException if access checking fails
+         *                                or if the method's variable arity modifier bit
+         *                                is set and {@code asVarargsCollector} fails
          * @exception SecurityException if a security manager is present and it
          *                              <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
          * @throws NullPointerException if any argument is null
@@ -641,6 +659,7 @@
             String name = "<init>";
             MemberName ctor = resolveOrFail(refc, name, type, false, false, lookupClassOrNull());
             assert(ctor.isConstructor());
+            checkSecurityManager(refc, ctor);  // stack walk magic: do not refactor
             checkAccess(refc, ctor);
             MethodHandle rawMH = MethodHandleImpl.findMethod(ctor, false, lookupClassOrNull());
             MethodHandle allocMH = MethodHandleImpl.makeAllocator(rawMH);
@@ -658,7 +677,7 @@
                 int arity = type.parameterCount();
                 return mh.asVarargsCollector(type.parameterType(arity-1));
             } else {
-                throw new InternalError("already varargs, but template is not: "+mh);
+                return mh.asFixedArity();
             }
         }
 
@@ -690,6 +709,8 @@
          * @return the desired method handle
          * @throws NoSuchMethodException if the method does not exist
          * @throws IllegalAccessException if access checking fails
+         *                                or if the method's variable arity modifier bit
+         *                                is set and {@code asVarargsCollector} fails
          * @exception SecurityException if a security manager is present and it
          *                              <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
          * @throws NullPointerException if any argument is null
@@ -698,6 +719,7 @@
                                         Class<?> specialCaller) throws NoSuchMethodException, IllegalAccessException {
             checkSpecialCaller(specialCaller);
             MemberName method = resolveOrFail(refc, name, type, false, false, specialCaller);
+            checkSecurityManager(refc, method);  // stack walk magic: do not refactor
             checkMethod(refc, method, false);
             MethodHandle mh = MethodHandleImpl.findMethod(method, false, specialCaller);
             return restrictReceiver(method, mh, specialCaller);
@@ -721,7 +743,9 @@
          * @throws NullPointerException if any argument is null
          */
         public MethodHandle findGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
-            return makeAccessor(refc, name, type, false, false);
+            MemberName field = resolveOrFail(refc, name, type, false);
+            checkSecurityManager(refc, field);  // stack walk magic: do not refactor
+            return makeAccessor(refc, field, false, false, 0);
         }
 
         /**
@@ -742,7 +766,9 @@
          * @throws NullPointerException if any argument is null
          */
         public MethodHandle findSetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
-            return makeAccessor(refc, name, type, false, true);
+            MemberName field = resolveOrFail(refc, name, type, false);
+            checkSecurityManager(refc, field);  // stack walk magic: do not refactor
+            return makeAccessor(refc, field, false, true, 0);
         }
 
         /**
@@ -762,7 +788,9 @@
          * @throws NullPointerException if any argument is null
          */
         public MethodHandle findStaticGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
-            return makeAccessor(refc, name, type, true, false);
+            MemberName field = resolveOrFail(refc, name, type, true);
+            checkSecurityManager(refc, field);  // stack walk magic: do not refactor
+            return makeAccessor(refc, field, false, false, 1);
         }
 
         /**
@@ -782,7 +810,9 @@
          * @throws NullPointerException if any argument is null
          */
         public MethodHandle findStaticSetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
-            return makeAccessor(refc, name, type, true, true);
+            MemberName field = resolveOrFail(refc, name, type, true);
+            checkSecurityManager(refc, field);  // stack walk magic: do not refactor
+            return makeAccessor(refc, field, false, true, 1);
         }
 
         /**
@@ -805,10 +835,13 @@
          * <p>
          * This is equivalent to the following code:
          * <blockquote><pre>
-MethodHandle mh0 = {@link #findVirtual findVirtual}(defc, name, type);
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
+...
+MethodHandle mh0 = lookup().{@link #findVirtual findVirtual}(defc, name, type);
 MethodHandle mh1 = mh0.{@link MethodHandle#bindTo bindTo}(receiver);
 MethodType mt1 = mh1.type();
-if (mh0.isVarargsCollector() && mt1.parameterCount() > 0) {
+if (mh0.isVarargsCollector())
   mh1 = mh1.asVarargsCollector(mt1.parameterType(mt1.parameterCount()-1));
 return mh1;
          * </pre></blockquote>
@@ -822,6 +855,8 @@
          * @return the desired method handle
          * @throws NoSuchMethodException if the method does not exist
          * @throws IllegalAccessException if access checking fails
+         *                                or if the method's variable arity modifier bit
+         *                                is set and {@code asVarargsCollector} fails
          * @exception SecurityException if a security manager is present and it
          *                              <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
          * @throws NullPointerException if any argument is null
@@ -829,13 +864,12 @@
         public MethodHandle bind(Object receiver, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
             Class<? extends Object> refc = receiver.getClass(); // may get NPE
             MemberName method = resolveOrFail(refc, name, type, false);
+            checkSecurityManager(refc, method);  // stack walk magic: do not refactor
             checkMethod(refc, method, false);
             MethodHandle dmh = MethodHandleImpl.findMethod(method, true, lookupClassOrNull());
             MethodHandle bmh = MethodHandleImpl.bindReceiver(dmh, receiver);
             if (bmh == null)
                 throw method.makeAccessException("no access", this);
-            if (dmh.type().parameterCount() == 0)
-                return dmh;  // bound the trailing parameter; no varargs possible
             return fixVarargs(bmh, dmh);
         }
 
@@ -856,6 +890,8 @@
          * @param m the reflected method
          * @return a method handle which can invoke the reflected method
          * @throws IllegalAccessException if access checking fails
+         *                                or if the method's variable arity modifier bit
+         *                                is set and {@code asVarargsCollector} fails
          * @throws NullPointerException if the argument is null
          */
         public MethodHandle unreflect(Method m) throws IllegalAccessException {
@@ -884,6 +920,8 @@
          * @param specialCaller the class nominally calling the method
          * @return a method handle which can invoke the reflected method
          * @throws IllegalAccessException if access checking fails
+         *                                or if the method's variable arity modifier bit
+         *                                is set and {@code asVarargsCollector} fails
          * @throws NullPointerException if any argument is null
          */
         public MethodHandle unreflectSpecial(Method m, Class<?> specialCaller) throws IllegalAccessException {
@@ -913,6 +951,8 @@
          * @param c the reflected constructor
          * @return a method handle which can invoke the reflected constructor
          * @throws IllegalAccessException if access checking fails
+         *                                or if the method's variable arity modifier bit
+         *                                is set and {@code asVarargsCollector} fails
          * @throws NullPointerException if the argument is null
          */
         public MethodHandle unreflectConstructor(Constructor c) throws IllegalAccessException {
@@ -939,7 +979,7 @@
          * @throws NullPointerException if the argument is null
          */
         public MethodHandle unreflectGetter(Field f) throws IllegalAccessException {
-            return makeAccessor(f.getDeclaringClass(), new MemberName(f), f.isAccessible(), false);
+            return makeAccessor(f.getDeclaringClass(), new MemberName(f), f.isAccessible(), false, -1);
         }
 
         /**
@@ -957,7 +997,7 @@
          * @throws NullPointerException if the argument is null
          */
         public MethodHandle unreflectSetter(Field f) throws IllegalAccessException {
-            return makeAccessor(f.getDeclaringClass(), new MemberName(f), f.isAccessible(), true);
+            return makeAccessor(f.getDeclaringClass(), new MemberName(f), f.isAccessible(), true, -1);
         }
 
         /// Helper methods, all package-private.
@@ -993,6 +1033,46 @@
                 throw new MemberName(refc).makeAccessException("symbolic reference class is not public", this);
         }
 
+        /**
+         * Perform necessary <a href="MethodHandles.Lookup.html#secmgr">access checks</a>.
+         * This function performs stack walk magic: do not refactor it.
+         */
+        void checkSecurityManager(Class<?> refc, MemberName m) {
+            SecurityManager smgr = System.getSecurityManager();
+            if (smgr == null)  return;
+            if (allowedModes == TRUSTED)  return;
+            // Step 1:
+            smgr.checkMemberAccess(refc, Member.PUBLIC);
+            // Step 2:
+            if (!VerifyAccess.classLoaderIsAncestor(lookupClass, refc))
+                smgr.checkPackageAccess(VerifyAccess.getPackageName(refc));
+            // Step 3:
+            if (m.isPublic()) return;
+            Class<?> defc = m.getDeclaringClass();
+            smgr.checkMemberAccess(defc, Member.DECLARED);  // STACK WALK HERE
+            // Step 4:
+            if (defc != refc)
+                smgr.checkPackageAccess(VerifyAccess.getPackageName(defc));
+
+            // Comment from SM.checkMemberAccess, where which=DECLARED:
+            /*
+             * stack depth of 4 should be the caller of one of the
+             * methods in java.lang.Class that invoke checkMember
+             * access. The stack should look like:
+             *
+             * someCaller                        [3]
+             * java.lang.Class.someReflectionAPI [2]
+             * java.lang.Class.checkMemberAccess [1]
+             * SecurityManager.checkMemberAccess [0]
+             *
+             */
+            // For us it is this stack:
+            // someCaller                        [3]
+            // Lookup.findSomeMember             [2]
+            // Lookup.checkSecurityManager       [1]
+            // SecurityManager.checkMemberAccess [0]
+        }
+
         void checkMethod(Class<?> refc, MemberName m, boolean wantStatic) throws IllegalAccessException {
             String message;
             if (m.isConstructor())
@@ -1085,19 +1165,14 @@
             return fixVarargs(narrowMH, mh);
         }
 
-        MethodHandle makeAccessor(Class<?> refc, String name, Class<?> type,
-                                  boolean isStatic, boolean isSetter) throws NoSuchFieldException, IllegalAccessException {
-            MemberName field = resolveOrFail(refc, name, type, isStatic);
-            if (isStatic != field.isStatic())
-                throw field.makeAccessException(isStatic
+        MethodHandle makeAccessor(Class<?> refc, MemberName field,
+                                  boolean trusted, boolean isSetter,
+                                  int checkStatic) throws IllegalAccessException {
+            assert(field.isField());
+            if (checkStatic >= 0 && (checkStatic != 0) != field.isStatic())
+                throw field.makeAccessException((checkStatic != 0)
                                                 ? "expected a static field"
                                                 : "expected a non-static field", this);
-            return makeAccessor(refc, field, false, isSetter);
-        }
-
-        MethodHandle makeAccessor(Class<?> refc, MemberName field,
-                                  boolean trusted, boolean isSetter) throws IllegalAccessException {
-            assert(field.isField());
             if (trusted)
                 return MethodHandleImpl.accessField(field, isSetter, lookupClassOrNull());
             checkAccess(refc, field);
@@ -1139,50 +1214,51 @@
 
     /**
      * Produces a method handle which will invoke any method handle of the
-     * given {@code type} on a standard set of {@code Object} type arguments
-     * and a single trailing {@code Object[]} array.
+     * given {@code type}, with a given number of trailing arguments replaced by
+     * 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
+     * <li>zero or more leading values (counted by {@code leadingArgCount})
+     * <li>an {@code Object[]} array containing trailing arguments
      * </ul>
      * <p>
-     * The invoker will behave like a call to {@link MethodHandle#invoke invoke} with
+     * The invoker will invoke its target like a call to {@link MethodHandle#invoke invoke} with
      * the indicated {@code type}.
      * That is, if the target is exactly of the given {@code type}, it will behave
      * like {@code invokeExact}; otherwise it behave as if {@link MethodHandle#asType asType}
      * is used to convert the target to the required {@code type}.
      * <p>
      * The type of the returned invoker will not be the given {@code type}, but rather
-     * will have all parameter and return types replaced by {@code Object}, except for
-     * the last parameter type, which will be the array type {@code Object[]}.
+     * will have all parameters except the first {@code leadingArgCount}
+     * replaced by a single array of type {@code Object[]}, which will be
+     * the final parameter.
      * <p>
-     * Before invoking its target, the invoker will spread the varargs array, apply
+     * Before invoking its target, the invoker will spread the final array, apply
      * reference casts as necessary, and unbox and widen 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 method is equivalent to the following code (though it may be more efficient):
      * <p><blockquote><pre>
 MethodHandle invoker = MethodHandles.invoker(type);
-int spreadArgCount = type.parameterCount - objectArgCount;
+int spreadArgCount = type.parameterCount() - leadingArgCount;
 invoker = invoker.asSpreader(Object[].class, spreadArgCount);
 return invoker;
      * </pre></blockquote>
      * <p>
      * This method throws no reflective or security exceptions.
      * @param type the desired target type
-     * @param objectArgCount number of fixed (non-varargs) {@code Object} arguments
+     * @param leadingArgCount number of fixed arguments, to be passed unchanged to the target
      * @return a method handle suitable for invoking any method handle of the given type
+     * @throws NullPointerException if {@code type} is null
+     * @throws IllegalArgumentException if {@code leadingArgCount} is not in
+     *                  the range from 0 to {@code type.parameterCount()} inclusive
      */
     static public
-    MethodHandle spreadInvoker(MethodType type, int objectArgCount) {
-        if (objectArgCount < 0 || objectArgCount > type.parameterCount())
-            throw new IllegalArgumentException("bad argument count "+objectArgCount);
-        return type.invokers().spreadInvoker(objectArgCount);
+    MethodHandle spreadInvoker(MethodType type, int leadingArgCount) {
+        if (leadingArgCount < 0 || leadingArgCount > type.parameterCount())
+            throw new IllegalArgumentException("bad argument count "+leadingArgCount);
+        return type.invokers().spreadInvoker(leadingArgCount);
     }
 
     /**
@@ -1212,7 +1288,7 @@
      * method handle values, as long as they are compatible with the type of {@code X}.
      * <p>
      * <em>(Note:  The invoker method is not available via the Core Reflection API.
-     * An attempt to call {@linkplain java.lang.reflect.Method#invoke Method.invoke}
+     * An attempt to call {@linkplain java.lang.reflect.Method#invoke java.lang.reflect.Method.invoke}
      * on the declared {@code invokeExact} or {@code invoke} method will raise an
      * {@link java.lang.UnsupportedOperationException UnsupportedOperationException}.)</em>
      * <p>
@@ -1232,12 +1308,18 @@
      * exactly equal to the desired type, except that it will accept
      * an additional leading argument of type {@code MethodHandle}.
      * <p>
-     * Before invoking its target, the invoker will apply reference casts as
+     * Before invoking its target, if the target differs from the expected type,
+     * the invoker will apply reference casts as
      * necessary and box, unbox, or widen primitive values, as if by {@link MethodHandle#asType asType}.
      * Similarly, the return value will be converted as necessary.
      * If the target is a {@linkplain MethodHandle#asVarargsCollector variable arity method handle},
      * the required arity conversion will be made, again as if by {@link MethodHandle#asType asType}.
      * <p>
+     * A {@linkplain MethodType#genericMethodType general method type},
+     * mentions only {@code Object} arguments and return values.
+     * An invoker for such a type is capable of calling any method handle
+     * of the same arity as the general type.
+     * <p>
      * This method is equivalent to the following code (though it may be more efficient):
      * <p><blockquote><pre>
 publicLookup().findVirtual(MethodHandle.class, "invoke", type)
@@ -1253,18 +1335,9 @@
     }
 
     /**
-     * <em>Temporary alias</em> for {@link #invoker}, for backward compatibility with some versions of JSR 292.
-     * @deprecated Will be removed for JSR 292 Proposed Final Draft.
-     */
-    public static
-    MethodHandle genericInvoker(MethodType type) {
-        return invoker(type);
-    }
-
-    /**
      * Perform value checking, exactly as if for an adapted method handle.
      * It is assumed that the given value is either null, of type T0,
-     * or (if T0 is primitive) of the wrapper type corresponding to T0.
+     * or (if T0 is primitive) of the wrapper class corresponding to T0.
      * The following checks and conversions are made:
      * <ul>
      * <li>If T0 and T1 are references, then a cast to T1 is applied.
@@ -1272,11 +1345,11 @@
      * <li>If T0 and T1 are primitives, then a widening or narrowing
      *     conversion is applied, if one exists.
      * <li>If T0 is a primitive and T1 a reference, and
-     *     T0 has a wrapper type TW, a boxing conversion to TW is applied,
+     *     T0 has a wrapper class TW, a boxing conversion to TW is applied,
      *     possibly followed by a reference conversion.
      *     T1 must be TW or a supertype.
      * <li>If T0 is a reference and T1 a primitive, and
-     *     T1 has a wrapper type TW, an unboxing conversion is applied,
+     *     T1 has a wrapper class TW, an unboxing conversion is applied,
      *     possibly preceded by a reference conversion.
      *     T0 must be TW or a supertype.
      * <li>If T1 is void, the return value is discarded
@@ -1289,6 +1362,7 @@
      * @return the value, converted if necessary
      * @throws java.lang.ClassCastException if a cast fails
      */
+    // FIXME: This is used in just one place.  Refactor away.
     static
     <T0, T1> T1 checkValue(Class<T0> t0, Class<T1> t1, Object value)
        throws ClassCastException
@@ -1317,6 +1391,8 @@
         return w1.convert(value, t1);
     }
 
+    // FIXME: Delete this.  It is used only for insertArguments & bindTo.
+    // Replace by a more standard check.
     static
     Object checkValue(Class<?> T1, Object value)
        throws ClassCastException
@@ -1333,137 +1409,53 @@
 
     /**
      * Produces a method handle which adapts the type of the
-     * 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 report a type
-     * which is equal to the desired new type.
-     * <p>
-     * If the original type and new type are equal, returns target.
-     * <p>
-     * The following conversions are applied as needed both to
-     * 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.
-     * Given those types T0, T1, one of the following conversions is applied
-     * if possible:
-     * <ul>
-     * <li>If T0 and T1 are references, then a cast to T1 is applied.
-     *     (The types do not need to be related in any particular way.)
-     * <li>If T0 and T1 are primitives, then a Java method invocation
-     *     conversion (JLS 5.3) is applied, if one exists.
-     * <li>If T0 is a primitive and T1 a reference, a boxing
-     *     conversion is applied if one exists, possibly followed by
-     *     a reference conversion to a superclass.
-     *     T1 must be a wrapper class or a supertype of one.
-     * <li>If T0 is a reference and T1 a primitive, an unboxing
-     *     conversion will be applied at runtime, possibly followed
-     *     by a Java method invocation conversion (JLS 5.3)
-     *     on the primitive value.  (These are the widening conversions.)
-     *     T0 must be a wrapper class or a supertype of one.
-     *     (In the case where T0 is Object, these are the conversions
-     *     allowed by java.lang.reflect.Method.invoke.)
-     * <li>If the return type T1 is void, any returned value is discarded
-     * <li>If the return type T0 is void and T1 a reference, a null value is introduced.
-     * <li>If the return type T0 is void and T1 a primitive, a zero value is introduced.
-     * </ul>
-     * @param target the method handle to invoke after arguments are retyped
-     * @param newType the expected type of the new method handle
-     * @return a method handle which delegates to {@code target} after performing
-     *           any necessary argument conversions, and arranges for any
-     *           necessary return value conversions
-     * @throws NullPointerException if either argument is null
-     * @throws WrongMethodTypeException if the conversion cannot be made
-     * @see MethodHandle#asType
-     * @see MethodHandles#explicitCastArguments
-     */
-    public static
-    MethodHandle convertArguments(MethodHandle target, MethodType newType) {
-        if (!target.type().isConvertibleTo(newType)) {
-            throw new WrongMethodTypeException("cannot convert "+target+" to "+newType);
-        }
-        return MethodHandleImpl.convertArguments(target, newType, 1);
-    }
-
-    /**
-     * Produces a method handle which adapts the type of the
-     * given method handle to a new type by pairwise argument conversion.
+     * given method handle to a new type by pairwise argument and return type conversion.
      * The original type and new type must have the same number of arguments.
      * The resulting method handle is guaranteed to report a type
      * which is equal to the desired new type.
      * <p>
      * If the original type and new type are equal, returns target.
      * <p>
-     * The same conversions are allowed as for {@link #convertArguments convertArguments},
+     * The same conversions are allowed as for {@link MethodHandle#asType MethodHandle.asType},
      * and some additional conversions are also applied if those conversions fail.
-     * Given types T0, T1, one of the following conversions is applied
-     * in addition, if the conversions specified for {@code convertArguments}
-     * would be insufficient:
+     * Given types <em>T0</em>, <em>T1</em>, one of the following conversions is applied
+     * if possible, before or instead of any conversions done by {@code asType}:
      * <ul>
-     * <li>If T0 and T1 are references, and T1 is an interface type,
-     *     then the value of type T0 is passed as a T1 without a cast.
+     * <li>If <em>T0</em> and <em>T1</em> are references, and <em>T1</em> is an interface type,
+     *     then the value of type <em>T0</em> is passed as a <em>T1</em> without a cast.
      *     (This treatment of interfaces follows the usage of the bytecode verifier.)
-     * <li>If T0 and T1 are primitives and one is boolean,
-     *     the boolean is treated as a one-bit unsigned integer.
+     * <li>If <em>T0</em> is boolean and <em>T1</em> is another primitive,
+     *     the boolean is converted to a byte value, 1 for true, 0 for false.
      *     (This treatment follows the usage of the bytecode verifier.)
-     *     A conversion from another primitive type behaves as if
-     *     it first converts to byte, and then masks all but the low bit.
-     * <li>If a primitive value would be converted by {@code convertArguments}
-     *     using Java method invocation conversion (JLS 5.3),
-     *     Java casting conversion (JLS 5.5) may be used also.
-     *     This allows primitives to be narrowed as well as widened.
+     * <li>If <em>T1</em> is boolean and <em>T0</em> is another primitive,
+     *     <em>T0</em> is converted to byte via Java casting conversion (JLS 5.5),
+     *     and the low order bit of the result is tested, as if by {@code (x & 1) != 0}.
+     * <li>If <em>T0</em> and <em>T1</em> are primitives other than boolean,
+     *     then a Java casting conversion (JLS 5.5) is applied.
+     *     (Specifically, <em>T0</em> will convert to <em>T1</em> by
+     *     widening and/or narrowing.)
+     * <li>If <em>T0</em> is a reference and <em>T1</em> a primitive, an unboxing
+     *     conversion will be applied at runtime, possibly followed
+     *     by a Java casting conversion (JLS 5.5) on the primitive value,
+     *     possibly followed by a conversion from byte to boolean by testing
+     *     the low-order bit.
+     * <li>If <em>T0</em> is a reference and <em>T1</em> a primitive,
+     *     and if the reference is null at runtime, a zero value is introduced.
      * </ul>
      * @param target the method handle to invoke after arguments are retyped
      * @param newType the expected type of the new method handle
-     * @return a method handle which delegates to {@code target} after performing
+     * @return a method handle which delegates to the target after performing
      *           any necessary argument conversions, and arranges for any
      *           necessary return value conversions
      * @throws NullPointerException if either argument is null
      * @throws WrongMethodTypeException if the conversion cannot be made
      * @see MethodHandle#asType
-     * @see MethodHandles#convertArguments
      */
     public static
     MethodHandle explicitCastArguments(MethodHandle target, MethodType newType) {
         return MethodHandleImpl.convertArguments(target, newType, 2);
     }
 
-    /*
-      FIXME: Reconcile javadoc with 10/22/2010 EG notes on conversion:
-
-      Both converters arrange for their method handles to convert arguments
-      and return values.  The conversion rules are the same for arguments
-      and return values, and depend only on source and target types, S and
-      T.  The conversions allowed by castConvertArguments are a strict
-      superset of those performed by convertArguments.
-
-      In all cases, if S and T are references, a simple checkcast is done.
-      If neither S nor T is a primitive, no attempt is made to unbox and
-      box.  A failed conversion throws ClassCastException.
-
-      If T is void, the value is dropped.
-
-      For compatibility with reflection, if S is void and T is a reference,
-      a null value is produced.
-
-      For compatibility with reflection, if S is a reference and T is a
-      primitive, S is first unboxed and then undergoes primitive conversion.
-      In the case of 'convertArguments', only assignment conversion is
-      performed (no narrowing primitive conversion).
-
-      If S is a primitive, S is boxed, and then the above rules are applied.
-      If S and T are both primitives, the boxing will be undetectable; only
-      the primitive conversions will be apparent to the user.  The key point
-      is that if S is a primitive type, the implementation may box it and
-      treat is as Object, without loss of information, or it may use a "fast
-      path" which does not use boxing.
-
-      Notwithstanding the rules above, for compatibility with the verifier,
-      if T is an interface, it is treated as if it were Object.  [KEEP THIS?]
-
-      Also, for compatibility with the verifier, a boolean may be undergo
-      widening or narrowing conversion to any other primitive type.  [KEEP THIS?]
-    */
-
     /**
      * Produces a method handle which adapts the calling sequence of the
      * given method handle to a new type, by reordering the arguments.
@@ -1482,8 +1474,8 @@
      * <p>
      * No argument or return value conversions are applied.
      * The type of each incoming argument, as determined by {@code newType},
-     * must be identical to the type of the corresponding outgoing argument
-     * or arguments in the target method handle.
+     * must be identical to the type of the corresponding outgoing parameter
+     * or parameters in the target method handle.
      * The return type of {@code newType} must be identical to the return
      * type of the original target.
      * <p>
@@ -1495,25 +1487,33 @@
      * incoming arguments which are not mentioned in the reordering array
      * are may be any type, as determined only by {@code newType}.
      * <blockquote><pre>
-MethodType intfn1 = MethodType.methodType(int.class, int.class);
-MethodType intfn2 = MethodType.methodType(int.class, int.class, int.class);
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
+...
+MethodType intfn1 = methodType(int.class, int.class);
+MethodType intfn2 = methodType(int.class, int.class, int.class);
 MethodHandle sub = ... {int x, int y => x-y} ...;
 assert(sub.type().equals(intfn2));
-MethodHandle sub1 = MethodHandles.permuteArguments(sub, intfn2, 0, 1);
-MethodHandle rsub = MethodHandles.permuteArguments(sub, intfn2, 1, 0);
+MethodHandle sub1 = permuteArguments(sub, intfn2, 0, 1);
+MethodHandle rsub = permuteArguments(sub, intfn2, 1, 0);
 assert((int)rsub.invokeExact(1, 100) == 99);
 MethodHandle add = ... {int x, int y => x+y} ...;
 assert(add.type().equals(intfn2));
-MethodHandle twice = MethodHandles.permuteArguments(add, intfn1, 0, 0);
+MethodHandle twice = permuteArguments(add, intfn1, 0, 0);
 assert(twice.type().equals(intfn1));
 assert((int)twice.invokeExact(21) == 42);
      * </pre></blockquote>
      * @param target the method handle to invoke after arguments are reordered
      * @param newType the expected type of the new method handle
-     * @param reorder a string which controls the reordering
-     * @return a method handle which delegates to {@code target} after it
+     * @param reorder an index array which controls the reordering
+     * @return a method handle which delegates to the target after it
      *           drops unused arguments and moves and/or duplicates the other arguments
      * @throws NullPointerException if any argument is null
+     * @throws IllegalArgumentException if the index array length is not equal to
+     *                  the arity of the target, or if any index array element
+     *                  not a valid index for a parameter of {@code newType},
+     *                  or if two corresponding parameter types in
+     *                  {@code target.type()} and {@code newType} are not identical,
      */
     public static
     MethodHandle permuteArguments(MethodHandle target, MethodType newType, int... reorder) {
@@ -1548,78 +1548,13 @@
     }
 
     /**
-     * Equivalent to the following code:
-     * <p><blockquote><pre>
-     * int spreadPos = newType.parameterCount() - 1;
-     * Class&lt;?&gt; spreadType = newType.parameterType(spreadPos);
-     * int spreadCount = target.type().parameterCount() - spreadPos;
-     * MethodHandle adapter = target.asSpreader(spreadType, spreadCount);
-     * adapter = adapter.asType(newType);
-     * return adapter;
-     * </pre></blockquote>
-     * @param target the method handle to invoke after argument spreading
-     * @param newType the expected type of the new method handle
-     * @return a method handle which spreads its final argument,
-     *         before calling the original method handle
-     */
-    /*non-public*/ static
-    MethodHandle spreadArguments(MethodHandle target, MethodType newType) {
-        MethodType oldType = target.type();
-        int inargs  = newType.parameterCount();
-        int outargs = oldType.parameterCount();
-        int spreadPos = inargs - 1;
-        int numSpread = (outargs - spreadPos);
-        MethodHandle res = null;
-        if (spreadPos >= 0 && numSpread >= 0) {
-            res = MethodHandleImpl.spreadArgumentsFromPos(target, newType, spreadPos);
-        }
-        if (res == null) {
-            throw newIllegalArgumentException("cannot spread "+newType+" to " +oldType);
-        }
-        return res;
-    }
-
-    /**
-     * Equivalent to the following code:
-     * <p><blockquote><pre>
-     * int collectPos = target.type().parameterCount() - 1;
-     * Class&lt;?&gt; collectType = target.type().parameterType(collectPos);
-     * if (!collectType.isArray())  collectType = Object[].class;
-     * int collectCount = newType.parameterCount() - collectPos;
-     * MethodHandle adapter = target.asCollector(collectType, collectCount);
-     * adapter = adapter.asType(newType);
-     * return adapter;
-     * </pre></blockquote>
-     * @param target the method handle to invoke after argument collection
-     * @param newType the expected type of the new method handle
-     * @return a method handle which collects some trailing argument
-     *         into an array, before calling the original method handle
-     */
-    /*non-public*/ static
-    MethodHandle collectArguments(MethodHandle target, MethodType newType) {
-        MethodType oldType = target.type();
-        int inargs  = newType.parameterCount();
-        int outargs = oldType.parameterCount();
-        int collectPos = outargs - 1;
-        int numCollect = (inargs - collectPos);
-        if (collectPos < 0 || numCollect < 0)
-            throw newIllegalArgumentException("wrong number of arguments");
-        MethodHandle res = MethodHandleImpl.collectArguments(target, newType, collectPos, null);
-        if (res == null) {
-            throw newIllegalArgumentException("cannot collect from "+newType+" to " +oldType);
-        }
-        return res;
-    }
-
-    /**
      * Produces a method handle of the requested return type which returns the given
      * constant value every time it is invoked.
      * <p>
      * Before the method handle is returned, the passed-in value is converted to the requested type.
      * If the requested type is primitive, widening primitive conversions are attempted,
      * else reference conversions are attempted.
-     * <p>The returned method handle is equivalent to {@code identity(type).bindTo(value)},
-     * unless the type is {@code void}, in which case it is {@code identity(type)}.
+     * <p>The returned method handle is equivalent to {@code identity(type).bindTo(value)}.
      * @param type the return type of the desired method handle
      * @param value the value to return
      * @return a method handle of the given return type and no arguments, which always returns the given value
@@ -1641,7 +1576,6 @@
 
     /**
      * Produces a method handle which returns its sole argument when invoked.
-     * <p>The identity function for {@code void} takes no arguments and returns no values.
      * @param type the type of the sole parameter and return value of the desired method handle
      * @return a unary method handle which accepts and returns the given type
      * @throws NullPointerException if the argument is null
@@ -1661,11 +1595,15 @@
     }
 
     /**
-     * Produces a method handle which calls the original method handle {@code target},
-     * after inserting the given argument(s) at the given position.
-     * The formal parameters to {@code target} which will be supplied by those
-     * arguments are called <em>bound parameters</em>, because the new method
-     * will contain bindings for those parameters take from {@code values}.
+     * Provides a target method handle with one or more <em>bound arguments</em>
+     * in advance of the method handle's invocation.
+     * The formal parameters to the target corresponding to the bound
+     * arguments are called <em>bound parameters</em>.
+     * Returns a new method handle which saves away the bound arguments.
+     * When it is invoked, it receives arguments for any non-bound parameters,
+     * binds the saved arguments to their corresponding parameters,
+     * and calls the original target.
+     * <p>
      * The type of the new method handle will drop the types for the bound
      * parameters from the original target type, since the new method handle
      * will no longer require those arguments to be supplied by its callers.
@@ -1674,15 +1612,16 @@
      * If a bound parameter type is a primitive, the argument object
      * must be a wrapper, and will be unboxed to produce the primitive value.
      * <p>
-     * The  <i>pos</i> may range between zero and <i>N</i> (inclusively),
-     * where <i>N</i> is the number of argument types in resulting method handle
-     * (after bound parameter types are dropped).
+     * The {@code pos} argument selects which parameters are to be bound.
+     * It may range between zero and <i>N-L</i> (inclusively),
+     * where <i>N</i> is the arity of the target method handle
+     * and <i>L</i> is the length of the values array.
      * @param target the method handle to invoke after the argument is inserted
      * @param pos where to insert the argument (zero for the first)
      * @param values the series of arguments to insert
      * @return a method handle which inserts an additional argument,
      *         before calling the original method handle
-     * @throws NullPointerException if the {@code target} argument or the {@code values} array is null
+     * @throws NullPointerException if the target or the {@code values} array is null
      * @see MethodHandle#bindTo
      */
     public static
@@ -1715,15 +1654,17 @@
     }
 
     /**
-     * Produces a method handle which calls the original method handle,
-     * after dropping the given argument(s) at the given position.
-     * The type of the new method handle will insert the given argument
-     * type(s), at that position, into the original handle's type.
+     * Produces a method handle which will discard some dummy arguments
+     * before calling some other specified <i>target</i> method handle.
+     * The type of the new method handle will be the same as the target's type,
+     * except it will also include the dummy argument types,
+     * at some given position.
      * <p>
-     * The <i>pos</i> may range between zero and <i>N</i>,
-     * where <i>N</i> is the number of argument types in <i>target</i>,
-     * meaning to drop the first or last argument (respectively),
-     * or an argument somewhere in between.
+     * The {@code pos} argument may range between zero and <i>N</i>,
+     * where <i>N</i> is the arity of the target.
+     * If {@code pos} is zero, the dummy arguments will precede
+     * the target's real arguments; if {@code pos} is <i>N</i>
+     * they will come after.
      * <p>
      * <b>Example:</b>
      * <p><blockquote><pre>
@@ -1748,14 +1689,16 @@
      * @param pos position of first argument to drop (zero for the leftmost)
      * @return a method handle which drops arguments of the given types,
      *         before calling the original method handle
-     * @throws NullPointerException if the {@code target} argument is null,
+     * @throws NullPointerException if the target is null,
      *                              or if the {@code valueTypes} list or any of its elements is null
-     * @throws IllegalArgumentException if any of the {@code valueTypes} is {@code void.class}
+     * @throws IllegalArgumentException if any element of {@code valueTypes} is {@code void.class},
+     *                  or if {@code pos} is negative or greater than the arity of the target,
+     *                  or if the new method handle's type would have too many parameters
      */
     public static
     MethodHandle dropArguments(MethodHandle target, int pos, List<Class<?>> valueTypes) {
+        MethodType oldType = target.type();  // get NPE
         if (valueTypes.size() == 0)  return target;
-        MethodType oldType = target.type();
         int outargs = oldType.parameterCount();
         int inargs  = outargs + valueTypes.size();
         if (pos < 0 || pos >= inargs)
@@ -1768,15 +1711,17 @@
     }
 
     /**
-     * Produces a method handle which calls the original method handle,
-     * after dropping the given argument(s) at the given position.
-     * The type of the new method handle will insert the given argument
-     * type(s), at that position, into the original handle's type.
+     * Produces a method handle which will discard some dummy arguments
+     * before calling some other specified <i>target</i> method handle.
+     * The type of the new method handle will be the same as the target's type,
+     * except it will also include the dummy argument types,
+     * at some given position.
      * <p>
-     * The <i>pos</i> may range between zero and <i>N</i>,
-     * where <i>N</i> is the number of argument types in <i>target</i>,
-     * meaning to drop the first or last argument (respectively),
-     * or an argument somewhere in between.
+     * The {@code pos} argument may range between zero and <i>N</i>,
+     * where <i>N</i> is the arity of the target.
+     * If {@code pos} is zero, the dummy arguments will precede
+     * the target's real arguments; if {@code pos} is <i>N</i>
+     * they will come after.
      * <p>
      * <b>Example:</b>
      * <p><blockquote><pre>
@@ -1805,9 +1750,11 @@
      * @param pos position of first argument to drop (zero for the leftmost)
      * @return a method handle which drops arguments of the given types,
      *         before calling the original method handle
-     * @throws NullPointerException if the {@code target} argument is null,
+     * @throws NullPointerException if the target is null,
      *                              or if the {@code valueTypes} array or any of its elements is null
-     * @throws IllegalArgumentException if any of the {@code valueTypes} is {@code void.class}
+     * @throws IllegalArgumentException if any element of {@code valueTypes} is {@code void.class},
+     *                  or if {@code pos} is negative or greater than the arity of the target,
+     *                  or if the new method handle's type would have too many parameters
      */
     public static
     MethodHandle dropArguments(MethodHandle target, int pos, Class<?>... valueTypes) {
@@ -1815,19 +1762,23 @@
     }
 
     /**
-     * Adapts a target method handle {@code target} by pre-processing
+     * Adapts a target method handle 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 elements of the {@code filters} array.
-     * Null arguments in the array are ignored, and the corresponding arguments left unchanged.
+     * The first element of the filter array corresponds to the {@code pos}
+     * argument of the target, and so on in sequence.
+     * <p>
+     * Null arguments in the array are treated as identity functions,
+     * and the corresponding arguments left unchanged.
      * (If there are no non-null elements in the array, the original target is returned.)
      * Each filter 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
+     * the target, 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.
@@ -1835,6 +1786,7 @@
      * parameter type of the target.
      * <p>
      * It is an error if there are elements of {@code filters}
+     * (null or not)
      * which do not correspond to argument positions in the target.
      * <b>Example:</b>
      * <p><blockquote><pre>
@@ -1853,15 +1805,23 @@
 MethodHandle f2 = filterArguments(cat, 0, upcase, upcase);
 assertEquals("XY", (String) f2.invokeExact("x", "y")); // XY
      * </pre></blockquote>
+     * <p> Here is pseudocode for the resulting adapter:
+     * <blockquote><pre>
+     * V target(P... p, A[i]... a[i], B... b);
+     * A[i] filter[i](V[i]);
+     * T adapter(P... p, V[i]... v[i], B... b) {
+     *   return target(p..., f[i](v[i])..., b...);
+     * }
+     * </pre></blockquote>
      *
      * @param target the method handle to invoke after arguments are filtered
      * @param pos the position of the first argument to filter
      * @param filters method handles to call initially on filtered arguments
      * @return method handle which incorporates the specified argument filtering logic
-     * @throws NullPointerException if the {@code target} argument is null
+     * @throws NullPointerException if the target is null
      *                              or if the {@code filters} array is null
      * @throws IllegalArgumentException if a non-null element of {@code filters}
-     *          does not match a corresponding argument type of {@code target} as described above,
+     *          does not match a corresponding argument type of target as described above,
      *          or if the {@code pos+filters.length} is greater than {@code target.type().parameterCount()}
      */
     public static
@@ -1895,15 +1855,18 @@
     }
 
     /**
-     * Adapts a target method handle {@code target} by post-processing
-     * its return value with a unary filter function.
+     * Adapts a target method handle by post-processing
+     * its return value (if any) with a filter (another method handle).
+     * The result of the filter is returned from the adapter.
      * <p>
-     * If a filter {@code F} applies to the return value of
-     * the target method handle, then {@code F} must be a method handle which
-     * takes exactly one argument.  The return type of {@code F}
+     * If the target returns a value, the filter must accept that value as
+     * its only argument.
+     * If the target returns void, the filter must accept no arguments.
+     * <p>
+     * The return type of the filter
      * replaces the return type of the target
      * in the resulting adapted method handle.
-     * The argument type of {@code F} must be identical to the
+     * The argument type of the filter (if any) must be identical to the
      * return type of the target.
      * <b>Example:</b>
      * <p><blockquote><pre>
@@ -1918,12 +1881,35 @@
 MethodHandle f0 = filterReturnValue(cat, length);
 System.out.println((int) f0.invokeExact("x", "y")); // 2
      * </pre></blockquote>
+     * <p> Here is pseudocode for the resulting adapter:
+     * <blockquote><pre>
+     * V target(A...);
+     * T filter(V);
+     * T adapter(A... a) {
+     *   V v = target(a...);
+     *   return filter(v);
+     * }
+     * // and if the target has a void return:
+     * void target2(A...);
+     * T filter2();
+     * T adapter2(A... a) {
+     *   target2(a...);
+     *   return filter2();
+     * }
+     * // and if the filter has a void return:
+     * V target3(A...);
+     * void filter3(V);
+     * void adapter3(A... a) {
+     *   V v = target3(a...);
+     *   filter3(v);
+     * }
+     * </pre></blockquote>
      * @param target the method handle to invoke before filtering the return value
      * @param filter method handle to call on the return value
      * @return method handle which incorporates the specified return value filtering logic
      * @throws NullPointerException if either argument is null
-     * @throws IllegalArgumentException if {@code filter}
-     *          does not match the return type of {@code target} as described above
+     * @throws IllegalArgumentException if the argument list of {@code filter}
+     *          does not match the return type of target as described above
      */
     public static
     MethodHandle filterReturnValue(MethodHandle target, MethodHandle filter) {
@@ -1952,55 +1938,87 @@
     }
 
     /**
-     * Adapts a target method handle {@code target} by pre-processing
+     * Adapts a target method handle by pre-processing
      * some of its arguments, and then calling the target with
-     * the result of the pre-processing, plus all original arguments.
+     * the result of the pre-processing, inserted into the original
+     * sequence of arguments.
+     * <p>
+     * The pre-processing is performed by {@code combiner}, a second method handle.
+     * Of the arguments passed to the adapter, the first {@code N} arguments
+     * are copied to the combiner, which is then called.
+     * (Here, {@code N} is defined as the parameter count of the combiner.)
+     * After this, control passes to the target, with any result
+     * from the combiner inserted before the original {@code N} incoming
+     * arguments.
      * <p>
-     * The pre-processing is performed by a second method handle, the {@code combiner}.
-     * The first {@code N} arguments passed to the adapter,
-     * are copied to the combiner, which then produces a result.
-     * (Here, {@code N} is defined as the parameter count of the adapter.)
-     * After this, control passes to the {@code target}, with both the result
-     * of the combiner, and all the original incoming arguments.
+     * If the combiner returns a value, the first parameter type of the target
+     * must be identical with the return type of the combiner, and the next
+     * {@code N} parameter types of the target must exactly match the parameters
+     * of the combiner.
      * <p>
-     * The first argument type of the target must be identical with the
-     * return type of the combiner.
+     * If the combiner has a void return, no result will be inserted,
+     * and the first {@code N} parameter types of the target
+     * must exactly match the parameters of the combiner.
+     * <p>
      * The resulting adapter is the same type as the target, except that the
-     * initial argument type of the target is dropped.
+     * first parameter type is dropped,
+     * if it corresponds to the result of the combiner.
      * <p>
      * (Note that {@link #dropArguments(MethodHandle,int,List) dropArguments} can be used to remove any arguments
-     * that either the {@code combiner} or {@code target} does not wish to receive.
+     * that either the combiner or the target does not wish to receive.
      * If some of the incoming arguments are destined only for the combiner,
      * consider using {@link MethodHandle#asCollector asCollector} 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.
+     * <b>Example:</b>
+     * <p><blockquote><pre>
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
+...
+MethodHandle trace = publicLookup().findVirtual(java.io.PrintStream.class,
+  "println", methodType(void.class, String.class))
+    .bindTo(System.out);
+MethodHandle cat = lookup().findVirtual(String.class,
+  "concat", methodType(String.class, String.class));
+assertEquals("boojum", (String) cat.invokeExact("boo", "jum"));
+MethodHandle catTrace = foldArguments(cat, trace);
+// also prints "boo":
+assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
+     * </pre></blockquote>
      * <p> Here is pseudocode for the resulting adapter:
      * <blockquote><pre>
-     * // there are N arguments in the A sequence
+     * // there are N arguments in A...
      * T target(V, A[N]..., B...);
      * V combiner(A...);
      * T adapter(A... a, B... b) {
      *   V v = combiner(a...);
      *   return target(v, a..., b...);
      * }
+     * // and if the combiner has a void return:
+     * T target2(A[N]..., B...);
+     * void combiner2(A...);
+     * T adapter2(A... a, B... b) {
+     *   combiner2(a...);
+     *   return target2(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 NullPointerException if either argument is null
-     * @throws IllegalArgumentException if the first argument type of
-     *          {@code target} is not the same as {@code combiner}'s return type,
-     *          or if the following argument types of {@code target}
+     * @throws IllegalArgumentException if {@code combiner}'s return type
+     *          is non-void and not the same as the first argument type of
+     *          the target, or if the initial {@code N} argument types
+     *          of the target
+     *          (skipping one matching the {@code combiner}'s return type)
      *          are not identical with the argument types of {@code combiner}
      */
     public static
     MethodHandle foldArguments(MethodHandle target, MethodHandle combiner) {
+        int pos = 0;
         MethodType targetType = target.type();
         MethodType combinerType = combiner.type();
-        int foldPos = 0;  // always at the head, at present
+        int foldPos = pos;
         int foldArgs = combinerType.parameterCount();
         int foldVals = combinerType.returnType() == void.class ? 0 : 1;
         int afterInsertPos = foldPos + foldVals;
@@ -2049,7 +2067,7 @@
      * @throws NullPointerException if any argument is null
      * @throws IllegalArgumentException if {@code test} does not return boolean,
      *          or if all three method types do not match (with the return
-     *          type of {@code test} changed to match that of {@code target}).
+     *          type of {@code test} changed to match that of the target).
      */
     public static
     MethodHandle guardWithTest(MethodHandle test,
@@ -2159,229 +2177,4 @@
     MethodHandle throwException(Class<?> returnType, Class<? extends Throwable> exType) {
         return MethodHandleImpl.throwException(MethodType.methodType(returnType, exType));
     }
-
-    /**
-     * Produces an instance of the given single-method interface which redirects
-     * its calls to the given method handle.
-     * <p>
-     * A single-method interface is an interface which declares a unique method.
-     * When determining the unique method of a single-method interface,
-     * the public {@code Object} methods ({@code toString}, {@code equals}, {@code hashCode})
-     * are disregarded.  For example, {@link java.util.Comparator} is a single-method interface,
-     * even though it re-declares the {@code Object.equals} method.
-     * <p>
-     * The type must be public.  No additional access checks are performed.
-     * <p>
-     * The resulting instance of the required type will respond to
-     * invocation of the type's single abstract method by calling
-     * the given {@code target} on the incoming arguments,
-     * and returning or throwing whatever the {@code target}
-     * returns or throws.  The invocation will be as if by
-     * {@code target.invoke}.
-     * The target's type will be checked before the
-     * instance is created, as if by a call to {@code asType},
-     * which may result in a {@code WrongMethodTypeException}.
-     * <p>
-     * The wrapper instance will implement the requested interface
-     * and its super-types, but no other single-method interfaces.
-     * This means that the instance will not unexpectedly
-     * pass an {@code instanceof} test for any unrequested type.
-     * <p style="font-size:smaller;">
-     * <em>Implementation Note:</em>
-     * Therefore, each instance must implement a unique single-method interface.
-     * Implementations may not bundle together
-     * multiple single-method interfaces onto single implementation classes
-     * in the style of {@link java.awt.AWTEventMulticaster}.
-     * <p>
-     * The method handle may throw an <em>undeclared exception</em>,
-     * which means any checked exception (or other checked throwable)
-     * not declared by the requested type's single abstract method.
-     * If this happens, the throwable will be wrapped in an instance of
-     * {@link java.lang.reflect.UndeclaredThrowableException UndeclaredThrowableException}
-     * and thrown in that wrapped form.
-     * <p>
-     * Like {@link java.lang.Integer#valueOf Integer.valueOf},
-     * {@code asInstance} is a factory method whose results are defined
-     * by their behavior.
-     * It is not guaranteed to return a new instance for every call.
-     * <p>
-     * Because of the possibility of {@linkplain java.lang.reflect.Method#isBridge bridge methods}
-     * and other corner cases, the interface may also have several abstract methods
-     * with the same name but having distinct descriptors (types of returns and parameters).
-     * In this case, all the methods are bound in common to the one given {@code target}.
-     * The type check and effective {@code asType} conversion is applied to each
-     * method type descriptor, and all abstract methods are bound to the {@code target} in common.
-     * Beyond this type check, no further checks are made to determine that the
-     * abstract methods are related in any way.
-     * <p>
-     * Future versions of this API may accept additional types,
-     * such as abstract classes with single abstract methods.
-     * Future versions of this API may also equip wrapper instances
-     * with one or more additional public "marker" interfaces.
-     *
-     * @param target the method handle to invoke from the wrapper
-     * @param smType the desired type of the wrapper, a single-method interface
-     * @return a correctly-typed wrapper for the given {@code target}
-     * @throws NullPointerException if either argument is null
-     * @throws IllegalArgumentException if the {@code smType} is not a
-     *         valid argument to this method
-     * @throws WrongMethodTypeException if the {@code target} cannot
-     *         be converted to the type required by the requested interface
-     */
-    // Other notes to implementors:
-    // <p>
-    // No stable mapping is promised between the single-method interface and
-    // the implementation class C.  Over time, several implementation
-    // classes might be used for the same type.
-    // <p>
-    // If the implementation is able
-    // to prove that a wrapper of the required type
-    // has already been created for a given
-    // method handle, or for another method handle with the
-    // same behavior, the implementation may return that wrapper in place of
-    // a new wrapper.
-    // <p>
-    // This method is designed to apply to common use cases
-    // where a single method handle must interoperate with
-    // an interface that implements a function-like
-    // API.  Additional variations, such as single-abstract-method classes with
-    // private constructors, or interfaces with multiple but related
-    // entry points, must be covered by hand-written or automatically
-    // generated adapter classes.
-    //
-    public static
-    <T> T asInstance(final MethodHandle target, final Class<T> smType) {
-        // POC implementation only; violates the above contract several ways
-        final Method sm = getSingleMethod(smType);
-        if (sm == null)
-            throw new IllegalArgumentException("not a single-method interface: "+smType.getName());
-        MethodType smMT = MethodType.methodType(sm.getReturnType(), sm.getParameterTypes());
-        MethodHandle checkTarget = target.asType(smMT);  // make throw WMT
-        checkTarget = checkTarget.asType(checkTarget.type().changeReturnType(Object.class));
-        final MethodHandle vaTarget = checkTarget.asSpreader(Object[].class, smMT.parameterCount());
-        return smType.cast(Proxy.newProxyInstance(
-                smType.getClassLoader(),
-                new Class[]{ smType, WrapperInstance.class },
-                new InvocationHandler() {
-                    private Object getArg(String name) {
-                        if ((Object)name == "getWrapperInstanceTarget")  return target;
-                        if ((Object)name == "getWrapperInstanceType")    return smType;
-                        throw new AssertionError();
-                    }
-                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
-                        if (method.getDeclaringClass() == WrapperInstance.class)
-                            return getArg(method.getName());
-                        if (method.equals(sm))
-                            return vaTarget.invokeExact(args);
-                        if (isObjectMethod(method))
-                            return callObjectMethod(this, method, args);
-                        throw new InternalError();
-                    }
-                }));
-    }
-
-    /**
-     * Determines if the given object was produced by a call to {@link #asInstance asInstance}.
-     * @param x any reference
-     * @return true if the reference is not null and points to an object produced by {@code asInstance}
-     */
-    public static
-    boolean isWrapperInstance(Object x) {
-        return x instanceof WrapperInstance;
-    }
-
-    private static WrapperInstance asWrapperInstance(Object x) {
-        try {
-            if (x != null)
-                return (WrapperInstance) x;
-        } catch (ClassCastException ex) {
-        }
-        throw new IllegalArgumentException("not a wrapper instance");
-    }
-
-    /**
-     * Produces or recovers a target method handle which is behaviorally
-     * equivalent to the unique method of this wrapper instance.
-     * The object {@code x} must have been produced by a call to {@link #asInstance asInstance}.
-     * This requirement may be tested via {@link #isWrapperInstance isWrapperInstance}.
-     * @param x any reference
-     * @return a method handle implementing the unique method
-     * @throws IllegalArgumentException if the reference x is not to a wrapper instance
-     */
-    public static
-    MethodHandle wrapperInstanceTarget(Object x) {
-        return asWrapperInstance(x).getWrapperInstanceTarget();
-    }
-
-    /**
-     * Recovers the unique single-method interface type for which this wrapper instance was created.
-     * The object {@code x} must have been produced by a call to {@link #asInstance asInstance}.
-     * This requirement may be tested via {@link #isWrapperInstance isWrapperInstance}.
-     * @param x any reference
-     * @return the single-method interface type for which the wrapper was created
-     * @throws IllegalArgumentException if the reference x is not to a wrapper instance
-     */
-    public static
-    Class<?> wrapperInstanceType(Object x) {
-        return asWrapperInstance(x).getWrapperInstanceType();
-    }
-
-    private static
-    boolean isObjectMethod(Method m) {
-        switch (m.getName()) {
-        case "toString":
-            return (m.getReturnType() == String.class
-                    && m.getParameterTypes().length == 0);
-        case "hashCode":
-            return (m.getReturnType() == int.class
-                    && m.getParameterTypes().length == 0);
-        case "equals":
-            return (m.getReturnType() == boolean.class
-                    && m.getParameterTypes().length == 1
-                    && m.getParameterTypes()[0] == Object.class);
-        }
-        return false;
-    }
-
-    private static
-    Object callObjectMethod(Object self, Method m, Object[] args) {
-        assert(isObjectMethod(m)) : m;
-        switch (m.getName()) {
-        case "toString":
-            return self.getClass().getName() + "@" + Integer.toHexString(self.hashCode());
-        case "hashCode":
-            return System.identityHashCode(self);
-        case "equals":
-            return (self == args[0]);
-        }
-        return null;
-    }
-
-    private static
-    Method getSingleMethod(Class<?> smType) {
-        Method sm = null;
-        for (Method m : smType.getMethods()) {
-            int mod = m.getModifiers();
-            if (Modifier.isAbstract(mod)) {
-                if (sm != null && !isObjectMethod(sm))
-                    return null;  // too many abstract methods
-                sm = m;
-            }
-        }
-        if (!smType.isInterface() && getSingleConstructor(smType) == null)
-            return null;  // wrong kind of constructor
-        return sm;
-    }
-
-    private static
-    Constructor getSingleConstructor(Class<?> smType) {
-        for (Constructor c : smType.getDeclaredConstructors()) {
-            if (c.getParameterTypes().length == 0) {
-                int mod = c.getModifiers();
-                if (Modifier.isPublic(mod) || Modifier.isProtected(mod))
-                    return c;
-            }
-        }
-        return null;
-    }
 }
--- a/jdk/src/share/classes/java/lang/invoke/MethodType.java	Thu May 26 20:20:03 2011 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/MethodType.java	Fri May 27 19:03:03 2011 -0700
@@ -273,7 +273,7 @@
      * @param objectArgCount number of parameters (excluding the final array parameter if any)
      * @param finalArray whether there will be a trailing array parameter, of type {@code Object[]}
      * @return a generally applicable method type, for all calls of the given fixed argument count and a collected array of further arguments
-     * @throws IllegalArgumentException if {@code objectArgCount} is negative or greater than 255 (or 254, if {@code finalArray})
+     * @throws IllegalArgumentException if {@code objectArgCount} is negative or greater than 255 (or 254, if {@code finalArray} is true)
      * @see #genericMethodType(int)
      */
     public static
@@ -455,7 +455,8 @@
     /**
      * Reports if this type contains a wrapper argument or return value.
      * Wrappers are types which box primitive values, such as {@link Integer}.
-     * The reference type {@code java.lang.Void} counts as a wrapper.
+     * The reference type {@code java.lang.Void} counts as a wrapper,
+     * if it occurs as a return type.
      * @return true if any of the types are wrappers
      */
     public boolean hasWrappers() {
@@ -649,13 +650,55 @@
     }
     /*non-public*/
     static boolean canConvert(Class<?> src, Class<?> dst) {
-        if (src == dst || dst == void.class)  return true;
-        if (src.isPrimitive() && dst.isPrimitive()) {
-        if (!Wrapper.forPrimitiveType(dst)
-                .isConvertibleFrom(Wrapper.forPrimitiveType(src)))
+        // short-circuit a few cases:
+        if (src == dst || dst == Object.class)  return true;
+        // the remainder of this logic is documented in MethodHandle.asType
+        if (src.isPrimitive()) {
+            // can force void to an explicit null, a la reflect.Method.invoke
+            // can also force void to a primitive zero, by analogy
+            if (src == void.class)  return true;  //or !dst.isPrimitive()?
+            Wrapper sw = Wrapper.forPrimitiveType(src);
+            if (dst.isPrimitive()) {
+                // P->P must widen
+                return Wrapper.forPrimitiveType(dst).isConvertibleFrom(sw);
+            } else {
+                // P->R must box and widen
+                return dst.isAssignableFrom(sw.wrapperType());
+            }
+        } else if (dst.isPrimitive()) {
+            // any value can be dropped
+            if (dst == void.class)  return true;
+            Wrapper dw = Wrapper.forPrimitiveType(dst);
+            // R->P must be able to unbox (from a dynamically chosen type) and widen
+            // For example:
+            //   Byte/Number/Comparable/Object -> dw:Byte -> byte.
+            //   Character/Comparable/Object -> dw:Character -> char
+            //   Boolean/Comparable/Object -> dw:Boolean -> boolean
+            // This means that dw must be cast-compatible with src.
+            if (src.isAssignableFrom(dw.wrapperType())) {
+                return true;
+            }
+            // The above does not work if the source reference is strongly typed
+            // to a wrapper whose primitive must be widened.  For example:
+            //   Byte -> unbox:byte -> short/int/long/float/double
+            //   Character -> unbox:char -> int/long/float/double
+            if (Wrapper.isWrapperType(src) &&
+                dw.isConvertibleFrom(Wrapper.forWrapperType(src))) {
+                // can unbox from src and then widen to dst
+                return true;
+            }
+            // We have already covered cases which arise due to runtime unboxing
+            // of a reference type which covers several wrapper types:
+            //   Object -> cast:Integer -> unbox:int -> long/float/double
+            //   Serializable -> cast:Byte -> unbox:byte -> byte/short/int/long/float/double
+            // An marginal case is Number -> dw:Character -> char, which would be OK if there were a
+            // subclass of Number which wraps a value that can convert to char.
+            // Since there is none, we don't need an extra check here to cover char or boolean.
             return false;
+        } else {
+            // R->R always works, since null is always valid dynamically
+            return true;
         }
-        return true;
     }
 
     /// Queries which have to do with the bytecode architecture
@@ -740,6 +783,7 @@
      * @param descriptor a bytecode-level type descriptor string "(T...)T"
      * @param loader the class loader in which to look up the types
      * @return a method type matching the bytecode-level type descriptor
+     * @throws NullPointerException if the string is null
      * @throws IllegalArgumentException if the string is not well-formed
      * @throws TypeNotPresentException if a named type cannot be found
      */
--- a/jdk/src/share/classes/java/lang/invoke/MutableCallSite.java	Thu May 26 20:20:03 2011 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/MutableCallSite.java	Fri May 27 19:03:03 2011 -0700
@@ -37,12 +37,13 @@
  * <p>
  * Here is an example of a mutable call site which introduces a
  * state variable into a method handle chain.
+ * <!-- JavaDocExamplesTest.testMutableCallSite -->
  * <blockquote><pre>
 MutableCallSite name = new MutableCallSite(MethodType.methodType(String.class));
 MethodHandle MH_name = name.dynamicInvoker();
-MethodType MT_str2 = MethodType.methodType(String.class, String.class);
+MethodType MT_str1 = MethodType.methodType(String.class);
 MethodHandle MH_upcase = MethodHandles.lookup()
-    .findVirtual(String.class, "toUpperCase", MT_str2);
+    .findVirtual(String.class, "toUpperCase", MT_str1);
 MethodHandle worker1 = MethodHandles.filterReturnValue(MH_name, MH_upcase);
 name.setTarget(MethodHandles.constant(String.class, "Rocky"));
 assertEquals("ROCKY", (String) worker1.invokeExact());
@@ -53,8 +54,10 @@
  * <p>
  * The same call site may be used in several places at once.
  * <blockquote><pre>
-MethodHandle MH_dear = MethodHandles.lookup()
-    .findVirtual(String.class, "concat", MT_str2).bindTo(", dear?");
+MethodType MT_str2 = MethodType.methodType(String.class, String.class);
+MethodHandle MH_cat = lookup().findVirtual(String.class,
+  "concat", methodType(String.class, String.class));
+MethodHandle MH_dear = MethodHandles.insertArguments(MH_cat, 1, ", dear?");
 MethodHandle worker2 = MethodHandles.filterReturnValue(MH_name, MH_dear);
 assertEquals("Fred, dear?", (String) worker2.invokeExact());
 name.setTarget(MethodHandles.constant(String.class, "Wilma"));
--- a/jdk/src/share/classes/java/lang/invoke/SwitchPoint.java	Thu May 26 20:20:03 2011 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/SwitchPoint.java	Fri May 27 19:03:03 2011 -0700
@@ -56,16 +56,17 @@
  * <p>
  * Here is an example of a switch point in action:
  * <blockquote><pre>
-MethodType MT_str2 = MethodType.methodType(String.class, String.class);
 MethodHandle MH_strcat = MethodHandles.lookup()
-    .findVirtual(String.class, "concat", MT_str2);
+    .findVirtual(String.class, "concat", MethodType.methodType(String.class, String.class));
 SwitchPoint spt = new SwitchPoint();
+assert(spt.isValid());
 // the following steps may be repeated to re-use the same switch point:
-MethodHandle worker1 = strcat;
-MethodHandle worker2 = MethodHandles.permuteArguments(strcat, MT_str2, 1, 0);
+MethodHandle worker1 = MH_strcat;
+MethodHandle worker2 = MethodHandles.permuteArguments(MH_strcat, MH_strcat.type(), 1, 0);
 MethodHandle worker = spt.guardWithTest(worker1, worker2);
 assertEquals("method", (String) worker.invokeExact("met", "hod"));
 SwitchPoint.invalidateAll(new SwitchPoint[]{ spt });
+assert(!spt.isValid());
 assertEquals("hodmet", (String) worker.invokeExact("met", "hod"));
  * </pre></blockquote>
  * <p style="font-size:smaller;">
@@ -125,6 +126,19 @@
     }
 
     /**
+     * Determines if this switch point is still valid.
+     * <p>
+     * Since invalidation is a global and immediate operation,
+     * this query must be sequenced with any
+     * other threads that could invalidate this switch point.
+     * It may therefore be expensive.
+     * @return true if this switch point has never been invalidated
+     */
+    public boolean isValid() {
+        return (mcs.getTarget() == K_true);
+    }
+
+    /**
      * Returns a method handle which always delegates either to the target or the fallback.
      * The method handle will delegate to the target exactly as long as the switch point is valid.
      * After that, it will permanently delegate to the fallback.
@@ -136,6 +150,7 @@
      * @param fallback the method handle selected by the switch point after it is invalidated
      * @return a combined method handle which always calls either the target or fallback
      * @throws NullPointerException if either argument is null
+     * @throws IllegalArgumentException if the two method types do not match
      * @see MethodHandles#guardWithTest
      */
     public MethodHandle guardWithTest(MethodHandle target, MethodHandle fallback) {
--- a/jdk/src/share/classes/java/lang/invoke/package-info.java	Thu May 26 20:20:03 2011 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/package-info.java	Fri May 27 19:03:03 2011 -0700
@@ -28,7 +28,8 @@
  * the Java core class libraries and virtual machine.
  *
  * <p>
- * Certain types in this package have special relations to dynamic
+ * As described in the Java Virtual Machine Specification,
+ * certain types in this package have special relations to dynamic
  * language support in the virtual machine:
  * <ul>
  * <li>The class {@link java.lang.invoke.MethodHandle MethodHandle} contains
@@ -42,177 +43,16 @@
  * </li>
  * </ul>
  *
- * <h2><a name="jvm_mods"></a>Corresponding JVM bytecode format changes</h2>
- * <em>The following low-level information is presented here as a preview of
- * changes being made to the Java Virtual Machine specification for JSR 292.
- * This information will be incorporated in a future version of the JVM specification.</em>
+ * <h2><a name="jvm_mods"></a>Summary of relevant Java Virtual Machine changes</h2>
+ * The following low-level information summarizes relevant parts of the
+ * Java Virtual Machine specification.  For full details, please see the
+ * current version of that specification.
  *
- * <h3><a name="indyinsn"></a>{@code invokedynamic} instruction format</h3>
- * In bytecode, an {@code invokedynamic} instruction is formatted as five bytes.
- * The first byte is the opcode 186 (hexadecimal {@code BA}).
- * The next two bytes are a constant pool index (in the same format as for the other {@code invoke} instructions).
- * The final two bytes are reserved for future use and required to be zero.
- * The constant pool reference of an {@code invokedynamic} instruction is to a entry
- * with tag {@code CONSTANT_InvokeDynamic} (decimal 18).  See below for its format.
- * The entry specifies the following information:
- * <ul>
- * <li>a bootstrap method (a {@link java.lang.invoke.MethodHandle MethodHandle} constant)</li>
- * <li>the dynamic invocation name (a UTF8 string)</li>
- * <li>the argument and return types of the call (encoded as a type descriptor in a UTF8 string)</li>
- * <li>optionally, a sequence of additional <em>static arguments</em> to the bootstrap method ({@code ldc}-type constants)</li>
- * </ul>
- * <p>
- * Each instance of an {@code invokedynamic} instruction is called a <em>dynamic call site</em>.
- * Multiple instances of an {@code invokedynamic} instruction can share a single
- * {@code CONSTANT_InvokeDynamic} entry.
- * In any case, distinct call sites always have distinct linkage state.
- * <p>
+ * Each occurrence of an {@code invokedynamic} instruction is called a <em>dynamic call site</em>.
+ * <h3><a name="indyinsn"></a>{@code invokedynamic} instructions</h3>
  * A dynamic call site is originally in an unlinked state.  In this state, there is
  * no target method for the call site to invoke.
- * A dynamic call site is linked by means of a bootstrap method,
- * as <a href="#bsm">described below</a>.
- *
- * <h3><a name="indycon"></a>constant pool entries for {@code invokedynamic} instructions</h3>
- * If a constant pool entry has the tag {@code CONSTANT_InvokeDynamic} (decimal 18),
- * it must contain exactly four more bytes after the tag.
- * These bytes are interpreted as two 16-bit indexes, in the usual {@code u2} format.
- * The first pair of bytes after the tag must be an index into a side table called the
- * <em>bootstrap method table</em>, which is stored in the {@code BootstrapMethods}
- * attribute as <a href="#bsmattr">described below</a>.
- * The second pair of bytes must be an index to a {@code CONSTANT_NameAndType}.
  * <p>
- * The first index specifies a bootstrap method used by the associated dynamic call sites.
- * The second index specifies the method name, argument types, and return type of the dynamic call site.
- * The structure of such an entry is therefore analogous to a {@code CONSTANT_Methodref},
- * except that the bootstrap method specifier reference replaces
- * the {@code CONSTANT_Class} reference of a {@code CONSTANT_Methodref} entry.
- *
- * <h3><a name="mtcon"></a>constant pool entries for {@linkplain java.lang.invoke.MethodType method types}</h3>
- * If a constant pool entry has the tag {@code CONSTANT_MethodType} (decimal 16),
- * it must contain exactly two more bytes, which must be an index to a {@code CONSTANT_Utf8}
- * entry which represents a method type descriptor.
- * <p>
- * The JVM will ensure that on first
- * execution of an {@code ldc} instruction for this entry, a {@link java.lang.invoke.MethodType MethodType}
- * will be created which represents the type descriptor.
- * Any classes mentioned in the {@code MethodType} will be loaded if necessary,
- * but not initialized.
- * Access checking and error reporting is performed exactly as it is for
- * references by {@code ldc} instructions to {@code CONSTANT_Class} constants.
- *
- * <h3><a name="mhcon"></a>constant pool entries for {@linkplain java.lang.invoke.MethodHandle method handles}</h3>
- * If a constant pool entry has the tag {@code CONSTANT_MethodHandle} (decimal 15),
- * it must contain exactly three more bytes.  The first byte after the tag is a subtag
- * value which must be in the range 1 through 9, and the last two must be an index to a
- * {@code CONSTANT_Fieldref}, {@code CONSTANT_Methodref}, or
- * {@code CONSTANT_InterfaceMethodref} entry which represents a field or method
- * for which a method handle is to be created.
- * Furthermore, the subtag value and the type of the constant index value
- * must agree according to the table below.
- * <p>
- * The JVM will ensure that on first execution of an {@code ldc} instruction
- * for this entry, a {@link java.lang.invoke.MethodHandle MethodHandle} will be created which represents
- * the field or method reference, according to the specific mode implied by the subtag.
- * <p>
- * As with {@code CONSTANT_Class} and {@code CONSTANT_MethodType} constants,
- * the {@code Class} or {@code MethodType} object which reifies the field or method's
- * type is created.  Any classes mentioned in this reification will be loaded if necessary,
- * but not initialized, and access checking and error reporting performed as usual.
- * <p>
- * Unlike the reflective {@code Lookup} API, there are no security manager calls made
- * when these constants are resolved.
- * <p>
- * The method handle itself will have a type and behavior determined by the subtag as follows:
- * <code>
- * <table border=1 cellpadding=5 summary="CONSTANT_MethodHandle subtypes">
- * <tr><th>N</th><th>subtag name</th><th>member</th><th>MH type</th><th>bytecode behavior</th><th>lookup expression</th></tr>
- * <tr><td>1</td><td>REF_getField</td><td>C.f:T</td><td>(C)T</td><td>getfield C.f:T</td>
- *               <td>{@linkplain java.lang.invoke.MethodHandles.Lookup#findGetter findGetter(C.class,"f",T.class)}</td></tr>
- * <tr><td>2</td><td>REF_getStatic</td><td>C.f:T</td><td>(&nbsp;)T</td><td>getstatic C.f:T</td>
- *               <td>{@linkplain java.lang.invoke.MethodHandles.Lookup#findStaticGetter findStaticGetter(C.class,"f",T.class)}</td></tr>
- * <tr><td>3</td><td>REF_putField</td><td>C.f:T</td><td>(C,T)void</td><td>putfield C.f:T</td>
- *               <td>{@linkplain java.lang.invoke.MethodHandles.Lookup#findSetter findSetter(C.class,"f",T.class)}</td></tr>
- * <tr><td>4</td><td>REF_putStatic</td><td>C.f:T</td><td>(T)void</td><td>putstatic C.f:T</td>
- *               <td>{@linkplain java.lang.invoke.MethodHandles.Lookup#findStaticSetter findStaticSetter(C.class,"f",T.class)}</td></tr>
- * <tr><td>5</td><td>REF_invokeVirtual</td><td>C.m(A*)T</td><td>(C,A*)T</td><td>invokevirtual C.m(A*)T</td>
- *               <td>{@linkplain java.lang.invoke.MethodHandles.Lookup#findVirtual findVirtual(C.class,"m",MT)}</td></tr>
- * <tr><td>6</td><td>REF_invokeStatic</td><td>C.m(A*)T</td><td>(C,A*)T</td><td>invokestatic C.m(A*)T</td>
- *               <td>{@linkplain java.lang.invoke.MethodHandles.Lookup#findStatic findStatic(C.class,"m",MT)}</td></tr>
- * <tr><td>7</td><td>REF_invokeSpecial</td><td>C.m(A*)T</td><td>(C,A*)T</td><td>invokespecial C.m(A*)T</td>
- *               <td>{@linkplain java.lang.invoke.MethodHandles.Lookup#findSpecial findSpecial(C.class,"m",MT,this.class)}</td></tr>
- * <tr><td>8</td><td>REF_newInvokeSpecial</td><td>C.&lt;init&gt;(A*)void</td><td>(A*)C</td><td>new C; dup; invokespecial C.&lt;init&gt;(A*)void</td>
- *               <td>{@linkplain java.lang.invoke.MethodHandles.Lookup#findConstructor findConstructor(C.class,MT)}</td></tr>
- * <tr><td>9</td><td>REF_invokeInterface</td><td>C.m(A*)T</td><td>(C,A*)T</td><td>invokeinterface C.m(A*)T</td>
- *               <td>{@linkplain java.lang.invoke.MethodHandles.Lookup#findVirtual findVirtual(C.class,"m",MT)}</td></tr>
- * </table>
- * </code>
- * Here, the type {@code C} is taken from the {@code CONSTANT_Class} reference associated
- * with the {@code CONSTANT_NameAndType} descriptor.
- * The field name {@code f} or method name {@code m} is taken from the {@code CONSTANT_NameAndType}
- * as is the result type {@code T} and (in the case of a method or constructor) the argument type sequence
- * {@code A*}.
- * <p>
- * Each method handle constant has an equivalent instruction sequence called its <em>bytecode behavior</em>.
- * In general, creating a method handle constant can be done in exactly the same circumstances that
- * the JVM would successfully resolve the symbolic references in the bytecode behavior.
- * Also, the type of a method handle constant is such that a valid {@code invokeExact} call
- * on the method handle has exactly the same JVM stack effects as the <em>bytecode behavior</em>.
- * Finally, calling a method handle constant on a valid set of arguments has exactly the same effect
- * and returns the same result (if any) as the corresponding <em>bytecode behavior</em>.
- * <p>
- * Each method handle constant also has an equivalent reflective <em>lookup expression</em>,
- * which is a query to a method in {@link java.lang.invoke.MethodHandles.Lookup}.
- * In the example lookup method expression given in the table above, the name {@code MT}
- * stands for a {@code MethodType} built from {@code T} and the sequence of argument types {@code A*}.
- * (Note that the type {@code C} is not prepended to the query type {@code MT} even if the member is non-static.)
- * In the case of {@code findSpecial}, the name {@code this.class} refers to the class containing
- * the bytecodes.
- * <p>
- * The special name {@code <clinit>} is not allowed.
- * The special name {@code <init>} is not allowed except for subtag 8 as shown.
- * <p>
- * The JVM verifier and linker apply the same access checks and restrictions for these references as for the hypothetical
- * bytecode instructions specified in the last column of the table.
- * A method handle constant will successfully resolve to a method handle if the symbolic references
- * of the corresponding bytecode instruction(s) would also resolve successfully.
- * Otherwise, an attempt to resolve the constant will throw equivalent linkage errors.
- * In particular, method handles to
- * private and protected members can be created in exactly those classes for which the corresponding
- * normal accesses are legal.
- * <p>
- * A constant may refer to a method or constructor with the {@code varargs}
- * bit (hexadecimal {@code 0x0080}) set in its modifier bitmask.
- * The method handle constant produced for such a method behaves as if
- * it were created by {@link java.lang.invoke.MethodHandle#asVarargsCollector asVarargsCollector}.
- * In other words, the constant method handle will exhibit variable arity,
- * when invoked via {@code MethodHandle.invoke}.
- * On the other hand, its behavior with respect to {@code invokeExact} will be the same
- * as if the {@code varargs} bit were not set.
- * <p>
- * Although the {@code CONSTANT_MethodHandle} and {@code CONSTANT_MethodType} constant types
- * resolve class names, they do not force class initialization.
- * Method handle constants for subtags {@code REF_getStatic}, {@code REF_putStatic}, and {@code REF_invokeStatic}
- * may force class initialization on their first invocation, just like the corresponding bytecodes.
- * <p>
- * The rules of section 5.4.3 of
- * <cite>The Java&trade; Virtual Machine Specification</cite>
- * apply to the resolution of {@code CONSTANT_MethodType}, {@code CONSTANT_MethodHandle},
- * and {@code CONSTANT_InvokeDynamic} constants,
- * by the execution of {@code invokedynamic} and {@code ldc} instructions.
- * (Roughly speaking, this means that every use of a constant pool entry
- * must lead to the same outcome.
- * If the resolution succeeds, the same object reference is produced
- * by every subsequent execution of the same instruction.
- * If the resolution of the constant causes an error to occur,
- * the same error will be re-thrown on every subsequent attempt
- * to use this particular constant.)
- * <p>
- * Constants created by the resolution of these constant pool types are not necessarily
- * interned.  Except for {@code CONSTANT_Class} and {@code CONSTANT_String} entries,
- * two distinct constant pool entries might not resolve to the same reference
- * even if they contain the same symbolic reference.
- *
- * <h2><a name="bsm"></a>Bootstrap Methods</h2>
  * Before the JVM can execute a dynamic call site (an {@code invokedynamic} instruction),
  * the call site must first be <em>linked</em>.
  * Linking is accomplished by calling a <em>bootstrap method</em>
@@ -234,15 +74,14 @@
  * call site execution.
  * Linkage does not trigger class initialization.
  * <p>
- * Next, the bootstrap method call is started, with at least four values being stacked:
+ * The bootstrap method is invoked on at least three values:
  * <ul>
- * <li>a {@code MethodHandle}, the resolved bootstrap method itself </li>
  * <li>a {@code MethodHandles.Lookup}, a lookup object on the <em>caller class</em> in which dynamic call site occurs </li>
  * <li>a {@code String}, the method name mentioned in the call site </li>
  * <li>a {@code MethodType}, the resolved type descriptor of the call </li>
- * <li>optionally, one or more <a href="#args">additional static arguments</a> </li>
+ * <li>optionally, between 1 and 251 additional static arguments taken from the constant pool </li>
  * </ul>
- * The method handle is then applied to the other values as if by
+ * Invocation is as if by
  * {@link java.lang.invoke.MethodHandle#invoke MethodHandle.invoke}.
  * The returned result must be a {@link java.lang.invoke.CallSite CallSite} (or a subclass).
  * The type of the call site's target must be exactly equal to the type
@@ -250,38 +89,15 @@
  * the bootstrap method.
  * The call site then becomes permanently linked to the dynamic call site.
  * <p>
- * As long as each bootstrap method can be correctly invoked
- * by <code>MethodHandle.invoke</code>, its detailed type is arbitrary.
- * For example, the first argument could be {@code Object}
- * instead of {@code MethodHandles.Lookup}, and the return type
- * could also be {@code Object} instead of {@code CallSite}.
- * (Note that the types and number of the stacked arguments limit
- * the legal kinds of bootstrap methods to appropriately typed
- * static methods and constructors of {@code CallSite} subclasses.)
- * <p>
- * After resolution, the linkage process may fail in a variety of ways.
- * All failures are reported by a {@link java.lang.BootstrapMethodError BootstrapMethodError},
+ * As documented in the JVM specification, all failures arising from
+ * the linkage of a dynamic call site are reported
+ * by a {@link java.lang.BootstrapMethodError BootstrapMethodError},
  * which is thrown as the abnormal termination of the dynamic call
  * site execution.
- * The following circumstances will cause this:
- * <ul>
- * <li>the index to the bootstrap method specifier is out of range </li>
- * <li>the bootstrap method cannot be resolved </li>
- * <li>the {@code MethodType} to pass to the bootstrap method cannot be resolved </li>
- * <li>a static argument to the bootstrap method cannot be resolved
- *     (i.e., a {@code CONSTANT_Class}, {@code CONSTANT_MethodType},
- *     or {@code CONSTANT_MethodHandle} argument cannot be linked) </li>
- * <li>the bootstrap method has the wrong arity,
- *     causing {@code MethodHandle.invoke} to throw {@code WrongMethodTypeException} </li>
- * <li>the bootstrap method has a wrong argument or return type </li>
- * <li>the bootstrap method invocation completes abnormally </li>
- * <li>the result from the bootstrap invocation is not a reference to
- *     an object of type {@link java.lang.invoke.CallSite CallSite} </li>
- * <li>the target of the {@code CallSite} does not have a target of
- *     the expected {@code MethodType} </li>
- * </ul>
+ * If this happens, the same error will the thrown for all subsequent
+ * attempts to execute the dynamic call site.
  *
- * <h3><a name="linktime"></a>timing of linkage</h3>
+ * <h3>timing of linkage</h3>
  * A dynamic call site is linked just before its first execution.
  * The bootstrap method call implementing the linkage occurs within
  * a thread that is attempting a first execution.
@@ -306,7 +122,7 @@
  * all threads.  Any other bootstrap method calls are allowed to complete, but their
  * results are ignored, and their dynamic call site invocations proceed with the originally
  * chosen target object.
- *
+
  * <p style="font-size:smaller;">
  * <em>Discussion:</em>
  * These rules do not enable the JVM to duplicate dynamic call sites,
@@ -315,64 +131,15 @@
  * just before its first invocation.
  * There is no way to undo the effect of a completed bootstrap method call.
  *
- * <h3><a name="bsmattr">the {@code BootstrapMethods} attribute </h3>
- * Each {@code CONSTANT_InvokeDynamic} entry contains an index which references
- * a bootstrap method specifier; all such specifiers are contained in a separate array.
- * This array is defined by a class attribute named {@code BootstrapMethods}.
- * The body of this attribute consists of a sequence of byte pairs, all interpreted as
- * as 16-bit counts or constant pool indexes, in the {@code u2} format.
- * The attribute body starts with a count of bootstrap method specifiers,
- * which is immediately followed by the sequence of specifiers.
- * <p>
- * Each bootstrap method specifier contains an index to a
- * {@code CONSTANT_MethodHandle} constant, which is the bootstrap
- * method itself.
- * This is followed by a count, and then a sequence (perhaps empty) of
- * indexes to <a href="#args">additional static arguments</a>
- * for the bootstrap method.
- * <p>
- * During class loading, the verifier must check the structure of the
- * {@code BootstrapMethods} attribute.  In particular, each constant
- * pool index must be of the correct type.  A bootstrap method index
- * must refer to a {@code CONSTANT_MethodHandle} (tag 15).
- * Every other index must refer to a valid operand of an
- * {@code ldc_w} or {@code ldc2_w} instruction (tag 3..8 or 15..16).
- *
- * <h3><a name="args">static arguments to the bootstrap method</h3>
- * An {@code invokedynamic} instruction specifies at least three arguments
- * to pass to its bootstrap method:
- * The caller class (expressed as a {@link java.lang.invoke.MethodHandles.Lookup Lookup object},
- * the name (extracted from the {@code CONSTANT_NameAndType} entry),
- * and the type (also extracted from the {@code CONSTANT_NameAndType} entry).
- * The {@code invokedynamic} instruction may specify additional metadata values
- * to pass to its bootstrap method.
- * Collectively, these values are called <em>static arguments</em> to the
- * {@code invokedynamic} instruction, because they are used once at link
- * time to determine the instruction's behavior on subsequent sets of
- * <em>dynamic arguments</em>.
- * <p>
- * Static arguments are used to communicate application-specific meta-data
- * to the bootstrap method.
- * Drawn from the constant pool, they may include references to classes, method handles,
- * strings, or numeric data that may be relevant to the task of linking that particular call site.
- * <p>
- * Static arguments are specified constant pool indexes stored in the {@code BootstrapMethods} attribute.
- * Before the bootstrap method is invoked, each index is used to compute an {@code Object}
- * reference to the indexed value in the constant pool.
- * The valid constant pool entries are listed in this table:
- * <code>
- * <table border=1 cellpadding=5 summary="Static argument types">
- * <tr><th>entry type</th><th>argument type</th><th>argument value</th></tr>
- * <tr><td>CONSTANT_String</td><td><code>java.lang.String</code></td><td>the indexed string literal</td></tr>
- * <tr><td>CONSTANT_Class</td><td><code>java.lang.Class</code></td><td>the indexed class, resolved</td></tr>
- * <tr><td>CONSTANT_Integer</td><td><code>java.lang.Integer</code></td><td>the indexed int value</td></tr>
- * <tr><td>CONSTANT_Long</td><td><code>java.lang.Long</code></td><td>the indexed long value</td></tr>
- * <tr><td>CONSTANT_Float</td><td><code>java.lang.Float</code></td><td>the indexed float value</td></tr>
- * <tr><td>CONSTANT_Double</td><td><code>java.lang.Double</code></td><td>the indexed double value</td></tr>
- * <tr><td>CONSTANT_MethodHandle</td><td><code>java.lang.invoke.MethodHandle</code></td><td>the indexed method handle constant</td></tr>
- * <tr><td>CONSTANT_MethodType</td><td><code>java.lang.invoke.MethodType</code></td><td>the indexed method type constant</td></tr>
- * </table>
- * </code>
+ * <h3>types of bootstrap methods</h3>
+ * As long as each bootstrap method can be correctly invoked
+ * by {@code MethodHandle.invoke}, its detailed type is arbitrary.
+ * For example, the first argument could be {@code Object}
+ * instead of {@code MethodHandles.Lookup}, and the return type
+ * could also be {@code Object} instead of {@code CallSite}.
+ * (Note that the types and number of the stacked arguments limit
+ * the legal kinds of bootstrap methods to appropriately typed
+ * static methods and constructors of {@code CallSite} subclasses.)
  * <p>
  * If a given {@code invokedynamic} instruction specifies no static arguments,
  * the instruction's bootstrap method will be invoked on three arguments,
@@ -380,7 +147,8 @@
  * If the {@code invokedynamic} instruction specifies one or more static arguments,
  * those values will be passed as additional arguments to the method handle.
  * (Note that because there is a limit of 255 arguments to any method,
- * at most 252 extra arguments can be supplied.)
+ * at most 251 extra arguments can be supplied, since the bootstrap method
+ * handle itself and its first three arguments must also be stacked.)
  * The bootstrap method will be invoked as if by either {@code MethodHandle.invoke}
  * or {@code invokeWithArguments}.  (There is no way to tell the difference.)
  * <p>
@@ -390,12 +158,11 @@
  * then some or all of the arguments specified here may be collected into a trailing array parameter.
  * (This is not a special rule, but rather a useful consequence of the interaction
  * between {@code CONSTANT_MethodHandle} constants, the modifier bit for variable arity methods,
- * and the {@code java.lang.invoke.MethodHandle#asVarargsCollector asVarargsCollector} transformation.)
+ * and the {@link java.lang.invoke.MethodHandle#asVarargsCollector asVarargsCollector} transformation.)
  * <p>
  * Given these rules, here are examples of legal bootstrap method declarations,
  * given various numbers {@code N} of extra arguments.
  * The first rows (marked {@code *}) will work for any number of extra arguments.
- * <code>
  * <table border=1 cellpadding=5 summary="Static argument types">
  * <tr><th>N</th><th>sample bootstrap method</th></tr>
  * <tr><td>*</td><td><code>CallSite bootstrap(Lookup caller, String name, MethodType type, Object... args)</code></td></tr>
@@ -408,7 +175,6 @@
  * <tr><td>2</td><td><code>CallSite bootstrap(Lookup caller, String name, MethodType type, String... args)</code></td></tr>
  * <tr><td>2</td><td><code>CallSite bootstrap(Lookup caller, String name, MethodType type, String x, int y)</code></td></tr>
  * </table>
- * </code>
  * The last example assumes that the extra arguments are of type
  * {@code CONSTANT_String} and {@code CONSTANT_Integer}, respectively.
  * The second-to-last example assumes that all extra arguments are of type
@@ -431,34 +197,6 @@
  * since each call site could be given its own unique bootstrap method.
  * Such a practice is likely to produce large class files and constant pools.
  *
- * <h2><a name="structs"></a>Structure Summary</h2>
- * <blockquote><pre>// summary of constant and attribute structures
-struct CONSTANT_MethodHandle_info {
-  u1 tag = 15;
-  u1 reference_kind;       // 1..8 (one of REF_invokeVirtual, etc.)
-  u2 reference_index;      // index to CONSTANT_Fieldref or *Methodref
-}
-struct CONSTANT_MethodType_info {
-  u1 tag = 16;
-  u2 descriptor_index;    // index to CONSTANT_Utf8, as in NameAndType
-}
-struct CONSTANT_InvokeDynamic_info {
-  u1 tag = 18;
-  u2 bootstrap_method_attr_index;  // index into BootstrapMethods_attr
-  u2 name_and_type_index;          // index to CONSTANT_NameAndType, as in Methodref
-}
-struct BootstrapMethods_attr {
- u2 name;  // CONSTANT_Utf8 = "BootstrapMethods"
- u4 size;
- u2 bootstrap_method_count;
- struct bootstrap_method_specifier {
-   u2 bootstrap_method_ref;  // index to CONSTANT_MethodHandle
-   u2 bootstrap_argument_count;
-   u2 bootstrap_arguments[bootstrap_argument_count];  // constant pool indexes
- } bootstrap_methods[bootstrap_method_count];
-}
- * </pre></blockquote>
- *
  * @author John Rose, JSR 292 EG
  * @since 1.7
  */
--- a/jdk/src/share/classes/sun/invoke/util/ValueConversions.java	Thu May 26 20:20:03 2011 -0700
+++ b/jdk/src/share/classes/sun/invoke/util/ValueConversions.java	Fri May 27 19:03:03 2011 -0700
@@ -198,27 +198,30 @@
         return unbox(Wrapper.forPrimitiveType(type), true, false);
     }
 
+    static private final Integer ZERO_INT = 0, ONE_INT = 1;
+
     /// Primitive conversions
     public static Number primitiveConversion(Wrapper wrap, Object x, boolean cast) {
         // Maybe merge this code with Wrapper.convert/cast.
         Number res = null;
         if (x == null) {
             if (!cast)  return null;
-            x = wrap.zero();
+            return ZERO_INT;
         }
         if (x instanceof Number) {
             res = (Number) x;
         } else if (x instanceof Boolean) {
-            res = ((boolean)x ? 1 : 0);
+            res = ((boolean)x ? ONE_INT : ZERO_INT);
         } else if (x instanceof Character) {
             res = (int)(char)x;
         } else {
             // this will fail with the required ClassCastException:
             res = (Number) x;
         }
-        if (!cast && !wrap.isConvertibleFrom(Wrapper.forWrapperType(x.getClass())))
+        Wrapper xwrap = Wrapper.findWrapperType(x.getClass());
+        if (xwrap == null || !cast && !wrap.isConvertibleFrom(xwrap))
             // this will fail with the required ClassCastException:
-            res = (Number) wrap.wrapperType().cast(x);
+            return (Number) wrap.wrapperType().cast(x);
         return res;
     }
 
--- a/jdk/src/share/classes/sun/invoke/util/VerifyAccess.java	Thu May 26 20:20:03 2011 -0700
+++ b/jdk/src/share/classes/sun/invoke/util/VerifyAccess.java	Fri May 27 19:03:03 2011 -0700
@@ -154,9 +154,10 @@
      * @return whether they are in the same package
      */
     public static boolean isSamePackage(Class<?> class1, Class<?> class2) {
+        assert(!class1.isArray() && !class2.isArray());
         if (class1 == class2)
             return true;
-        if (!loadersAreRelated(class1.getClassLoader(), class2.getClassLoader()))
+        if (!loadersAreRelated(class1.getClassLoader(), class2.getClassLoader(), false))
             return false;
         String name1 = class1.getName(), name2 = class2.getName();
         int dot = name1.lastIndexOf('.');
@@ -169,6 +170,16 @@
         return true;
     }
 
+    /** Return the package name for this class.
+     */
+    public static String getPackageName(Class<?> cls) {
+        assert(!cls.isArray());
+        String name = cls.getName();
+        int dot = name.lastIndexOf('.');
+        if (dot < 0)  return "";
+        return name.substring(0, dot);
+    }
+
     /**
      * Test if two classes are defined as part of the same package member (top-level class).
      * If this is true, they can share private access with each other.
@@ -193,18 +204,33 @@
         return pkgmem;
     }
 
-    private static boolean loadersAreRelated(ClassLoader loader1, ClassLoader loader2) {
-        if (loader1 == loader2 || loader1 == null || loader2 == null) {
+    private static boolean loadersAreRelated(ClassLoader loader1, ClassLoader loader2,
+                                             boolean loader1MustBeParent) {
+        if (loader1 == loader2 || loader1 == null
+                || (loader2 == null && !loader1MustBeParent)) {
             return true;
         }
-        for (ClassLoader scan1 = loader1;
-                scan1 != null; scan1 = scan1.getParent()) {
-            if (scan1 == loader2)  return true;
-        }
         for (ClassLoader scan2 = loader2;
                 scan2 != null; scan2 = scan2.getParent()) {
             if (scan2 == loader1)  return true;
         }
+        if (loader1MustBeParent)  return false;
+        // see if loader2 is a parent of loader1:
+        for (ClassLoader scan1 = loader1;
+                scan1 != null; scan1 = scan1.getParent()) {
+            if (scan1 == loader2)  return true;
+        }
         return false;
     }
+
+    /**
+     * Is the class loader of parentClass identical to, or an ancestor of,
+     * the class loader of childClass?
+     * @param parentClass
+     * @param childClass
+     * @return whether parentClass precedes or equals childClass in class loader order
+     */
+    public static boolean classLoaderIsAncestor(Class<?> parentClass, Class<?> childClass) {
+        return loadersAreRelated(parentClass.getClassLoader(), childClass.getClassLoader(), true);
+    }
 }
--- a/jdk/src/share/classes/sun/invoke/util/Wrapper.java	Thu May 26 20:20:03 2011 -0700
+++ b/jdk/src/share/classes/sun/invoke/util/Wrapper.java	Fri May 27 19:03:03 2011 -0700
@@ -135,7 +135,7 @@
      *  <li>any type converted to {@code void} (i.e., dropping a method call's value)
      *  <li>boxing conversion followed by widening reference conversion to {@code Object}
      *  </ul>
-     *  These are the cases allowed by MethodHandle.asType and convertArguments.
+     *  These are the cases allowed by MethodHandle.asType.
      */
     public boolean isConvertibleFrom(Wrapper source) {
         if (this == source)  return true;
--- a/jdk/test/java/lang/invoke/6998541/Test6998541.java	Thu May 26 20:20:03 2011 -0700
+++ b/jdk/test/java/lang/invoke/6998541/Test6998541.java	Fri May 27 19:03:03 2011 -0700
@@ -164,6 +164,7 @@
     private static boolean canDoAsType(Class<?> src, Class<?> dst) {
         if (src == dst)  return true;
         if (dst == void.class)  return true;
+        if (src == void.class)  return true;  // allow void->zero
         if (!src.isPrimitive() || !dst.isPrimitive())  return true;
         // primitive conversion works for asType only when it's widening
         if (src == boolean.class || dst == boolean.class)  return false;
@@ -451,7 +452,6 @@
     private final static MethodHandle mh_dv = mh(double.class );
 
     private static void void2prim(int i) throws Throwable {
-        if (!DO_CASTS)  return;
         assertEquals(        false, (boolean) mh_zv.invokeExact());  // void -> boolean
         assertEquals((byte)  0,     (byte)    mh_bv.invokeExact());  // void -> byte
         assertEquals((char)  0,     (char)    mh_cv.invokeExact());  // void -> char
@@ -463,15 +463,7 @@
     }
 
     private static void void2prim_invalid(double x) throws Throwable {
-        if (DO_CASTS)  return;
-        try { assertEquals(        false, (boolean) mh_zv.invokeExact()); fail(); } catch (NullPointerException _) {}  // void -> boolean
-        try { assertEquals((byte)  0,     (byte)    mh_bv.invokeExact()); fail(); } catch (NullPointerException _) {}  // void -> byte
-        try { assertEquals((char)  0,     (char)    mh_cv.invokeExact()); fail(); } catch (NullPointerException _) {}  // void -> char
-        try { assertEquals((short) 0,     (short)   mh_sv.invokeExact()); fail(); } catch (NullPointerException _) {}  // void -> short
-        try { assertEquals(        0,     (int)     mh_iv.invokeExact()); fail(); } catch (NullPointerException _) {}  // void -> int
-        try { assertEquals(        0L,    (long)    mh_jv.invokeExact()); fail(); } catch (NullPointerException _) {}  // void -> long
-        try { assertEquals(        0.0f,  (float)   mh_fv.invokeExact()); fail(); } catch (NullPointerException _) {}  // void -> float
-        try { assertEquals(        0.0d,  (double)  mh_dv.invokeExact()); fail(); } catch (NullPointerException _) {}  // void -> double
+        // no cases
     }
 
     private static MethodHandle mh_v(Class arg) { return mh(void.class, arg); }
--- a/jdk/test/java/lang/invoke/InvokeDynamicPrintArgs.java	Thu May 26 20:20:03 2011 -0700
+++ b/jdk/test/java/lang/invoke/InvokeDynamicPrintArgs.java	Fri May 27 19:03:03 2011 -0700
@@ -106,8 +106,10 @@
         "Done printing argument lists."
     };
 
+    private static boolean doPrint = true;
     private static void printArgs(Object bsmInfo, Object... args) {
-        System.out.println(bsmInfo+Arrays.deepToString(args));
+        String message = bsmInfo+Arrays.deepToString(args);
+        if (doPrint)  System.out.println(message);
     }
     private static MethodHandle MH_printArgs() throws ReflectiveOperationException {
         shouldNotCallThis();
@@ -129,11 +131,48 @@
         return lookup().findStatic(lookup().lookupClass(), "bsm", MT_bsm());
     }
 
-    private static CallSite bsm2(Lookup caller, String name, MethodType type, Object... arg) throws ReflectiveOperationException {
+    /* Example of a constant call site with user-data.
+     * In this case, the user data is exactly the BSM data.
+     * Note that a CCS with user data must use the "hooked" constructor
+     * to bind the CCS itself into the resulting target.
+     * A normal constructor would not allow a circular relation
+     * between the CCS and its target.
+     */
+    public static class PrintingCallSite extends ConstantCallSite {
+        final Lookup caller;
+        final String name;
+        final Object[] staticArgs;
+
+        PrintingCallSite(Lookup caller, String name, MethodType type, Object... staticArgs) throws Throwable {
+            super(type, MH_createTarget());
+            this.caller = caller;
+            this.name = name;
+            this.staticArgs = staticArgs;
+        }
+
+        public MethodHandle createTarget() {
+            try {
+                return lookup().bind(this, "runTarget", genericMethodType(0, true)).asType(type());
+            } catch (ReflectiveOperationException ex) {
+                throw new RuntimeException(ex);
+            }
+        }
+
+        public Object runTarget(Object... dynamicArgs) {
+            List<Object> bsmInfo = new ArrayList<>(Arrays.asList(caller, name, type()));
+            bsmInfo.addAll(Arrays.asList(staticArgs));
+            printArgs(bsmInfo, dynamicArgs);
+            return null;
+        }
+
+        private static MethodHandle MH_createTarget() throws ReflectiveOperationException {
+            shouldNotCallThis();
+            return lookup().findVirtual(lookup().lookupClass(), "createTarget", methodType(MethodHandle.class));
+        }
+    }
+    private static CallSite bsm2(Lookup caller, String name, MethodType type, Object... arg) throws Throwable {
         // ignore caller and name, but match the type:
-        List<Object> bsmInfo = new ArrayList<>(Arrays.asList(caller, name, type));
-        bsmInfo.addAll(Arrays.asList((Object[])arg));
-        return new ConstantCallSite(MH_printArgs().bindTo(bsmInfo).asCollector(Object[].class, type.parameterCount()).asType(type));
+        return new PrintingCallSite(caller, name, type, arg);
     }
     private static MethodType MT_bsm2() {
         shouldNotCallThis();
@@ -146,33 +185,33 @@
 
     private static MethodHandle INDY_nothing() throws Throwable {
         shouldNotCallThis();
-        return ((CallSite) MH_bsm().invokeGeneric(lookup(),
+        return ((CallSite) MH_bsm().invoke(lookup(),
                                                   "nothing", methodType(void.class)
                                                   )).dynamicInvoker();
     }
     private static MethodHandle INDY_foo() throws Throwable {
         shouldNotCallThis();
-        return ((CallSite) MH_bsm().invokeGeneric(lookup(),
+        return ((CallSite) MH_bsm().invoke(lookup(),
                                                   "foo", methodType(void.class, String.class)
                                                   )).dynamicInvoker();
     }
     private static MethodHandle INDY_bar() throws Throwable {
         shouldNotCallThis();
-        return ((CallSite) MH_bsm2().invokeGeneric(lookup(),
+        return ((CallSite) MH_bsm2().invoke(lookup(),
                                                   "bar", methodType(void.class, String.class, int.class)
                                                   , Void.class, "void type!", 1, 234.5F, 67.5, (long)89
                                                   )).dynamicInvoker();
     }
     private static MethodHandle INDY_bar2() throws Throwable {
         shouldNotCallThis();
-        return ((CallSite) MH_bsm2().invokeGeneric(lookup(),
+        return ((CallSite) MH_bsm2().invoke(lookup(),
                                                   "bar2", methodType(void.class, String.class, int.class)
                                                   , Void.class, "void type!", 1, 234.5F, 67.5, (long)89
                                                   )).dynamicInvoker();
     }
     private static MethodHandle INDY_baz() throws Throwable {
         shouldNotCallThis();
-        return ((CallSite) MH_bsm2().invokeGeneric(lookup(),
+        return ((CallSite) MH_bsm2().invoke(lookup(),
                                                   "baz", methodType(void.class, String.class, int.class, double.class)
                                                   , 1234.5
                                                   )).dynamicInvoker();
--- a/jdk/test/java/lang/invoke/InvokeGenericTest.java	Thu May 26 20:20:03 2011 -0700
+++ b/jdk/test/java/lang/invoke/InvokeGenericTest.java	Fri May 27 19:03:03 2011 -0700
@@ -314,7 +314,7 @@
         ArrayList<Class<?>> argTypes = new ArrayList<Class<?>>(targetType.parameterList());
         Collections.fill(argTypes.subList(beg, end), argType);
         MethodType ttype2 = MethodType.methodType(targetType.returnType(), argTypes);
-        return MethodHandles.convertArguments(target, ttype2);
+        return target.asType(ttype2);
     }
 
     // This lookup is good for all members in and under InvokeGenericTest.
@@ -378,7 +378,7 @@
         String[] args = { "one", "two" };
         MethodHandle mh = callable(Object.class, String.class);
         Object res; List resl;
-        res = resl = (List) mh.invokeGeneric((String)args[0], (Object)args[1]);
+        res = resl = (List) mh.invoke((String)args[0], (Object)args[1]);
         //System.out.println(res);
         assertEquals(Arrays.asList(args), res);
     }
--- a/jdk/test/java/lang/invoke/JavaDocExamplesTest.java	Thu May 26 20:20:03 2011 -0700
+++ b/jdk/test/java/lang/invoke/JavaDocExamplesTest.java	Fri May 27 19:03:03 2011 -0700
@@ -34,7 +34,7 @@
 $ $JAVA7X_HOME/bin/javac -cp $JUNIT4_JAR -d /tmp/Classes \
    $DAVINCI/sources/jdk/test/java/lang/invoke/JavaDocExamplesTest.java
 $ $JAVA7X_HOME/bin/java   -cp $JUNIT4_JAR:/tmp/Classes \
-   -Dtest.java.lang.invoke.JavaDocExamplesTest.verbosity=1 \
+   -DJavaDocExamplesTest.verbosity=1 \
      test.java.lang.invoke.JavaDocExamplesTest
 ----
 */
@@ -45,12 +45,10 @@
 import static java.lang.invoke.MethodHandles.*;
 import static java.lang.invoke.MethodType.*;
 
-import java.lang.reflect.*;
 import java.util.*;
 
 import org.junit.*;
 import static org.junit.Assert.*;
-import static org.junit.Assume.*;
 
 
 /**
@@ -60,11 +58,29 @@
     /** Wrapper for running the JUnit tests in this module.
      *  Put JUnit on the classpath!
      */
-    public static void main(String... ignore) {
-        org.junit.runner.JUnitCore.runClasses(JavaDocExamplesTest.class);
+    public static void main(String... ignore) throws Throwable {
+        System.out.println("can run this as:");
+        System.out.println("$ java org.junit.runner.JUnitCore "+JavaDocExamplesTest.class.getName());
+        new JavaDocExamplesTest().run();
+    }
+    public void run() throws Throwable {
+        testFindVirtual();
+        testPermuteArguments();
+        testDropArguments();
+        testFilterArguments();
+        testFoldArguments();
+        testMethodHandlesSummary();
+        testAsSpreader();
+        testAsCollector();
+        testAsVarargsCollector();
+        testAsFixedArity();
+        testAsTypeCornerCases();
+        testMutableCallSite();
     }
     // How much output?
-    static int verbosity = Integer.getInteger("test.java.lang.invoke.JavaDocExamplesTest.verbosity", 0);
+    static final Class<?> THIS_CLASS = JavaDocExamplesTest.class;
+    static int verbosity = Integer.getInteger(THIS_CLASS.getSimpleName()+".verbosity", 0);
+
 
 {}
 static final private Lookup LOOKUP = lookup();
@@ -74,17 +90,23 @@
 //     "hashCode", methodType(int.class));
 
 // form required if ReflectiveOperationException is intercepted:
-static final private MethodHandle CONCAT_2, HASHCODE_2;
+    static final private MethodHandle CONCAT_2, HASHCODE_2, ADD_2, SUB_2;
 static {
   try {
+    Class<?> THIS_CLASS = LOOKUP.lookupClass();
     CONCAT_2 = LOOKUP.findVirtual(String.class,
       "concat", methodType(String.class, String.class));
     HASHCODE_2 = LOOKUP.findVirtual(Object.class,
       "hashCode", methodType(int.class));
+    ADD_2 = LOOKUP.findStatic(THIS_CLASS, "add", methodType(int.class, int.class, int.class));
+    SUB_2 = LOOKUP.findStatic(THIS_CLASS, "sub", methodType(int.class, int.class, int.class));
    } catch (ReflectiveOperationException ex) {
      throw new RuntimeException(ex);
    }
 }
+    static int add(int x, int y) { return x + y; }
+    static int sub(int x, int y) { return x - y; }
+
 {}
 
     @Test public void testFindVirtual() throws Throwable {
@@ -101,6 +123,39 @@
 assertEquals("xy".hashCode(), (int) HASHCODE_3.invokeExact((Object)"xy"));
 {}
     }
+
+    @Test public void testPermuteArguments() throws Throwable {
+        {{
+{} /// JAVADOC
+MethodType intfn1 = methodType(int.class, int.class);
+MethodType intfn2 = methodType(int.class, int.class, int.class);
+MethodHandle sub = SUB_2;// ... {int x, int y => x-y} ...;
+assert(sub.type().equals(intfn2));
+MethodHandle sub1 = permuteArguments(sub, intfn2, 0, 1);
+MethodHandle rsub = permuteArguments(sub, intfn2, 1, 0);
+assert((int)rsub.invokeExact(1, 100) == 99);
+MethodHandle add = ADD_2;// ... {int x, int y => x+y} ...;
+assert(add.type().equals(intfn2));
+MethodHandle twice = permuteArguments(add, intfn1, 0, 0);
+assert(twice.type().equals(intfn1));
+assert((int)twice.invokeExact(21) == 42);
+            }}
+        {{
+{} /// JAVADOC
+MethodHandle cat = lookup().findVirtual(String.class,
+  "concat", methodType(String.class, String.class));
+assertEquals("xy", (String) cat.invokeExact("x", "y"));
+MethodHandle d0 = dropArguments(cat, 0, String.class);
+assertEquals("yz", (String) d0.invokeExact("x", "y", "z"));
+MethodHandle d1 = dropArguments(cat, 1, String.class);
+assertEquals("xz", (String) d1.invokeExact("x", "y", "z"));
+MethodHandle d2 = dropArguments(cat, 2, String.class);
+assertEquals("xy", (String) d2.invokeExact("x", "y", "z"));
+MethodHandle d12 = dropArguments(cat, 1, int.class, boolean.class);
+assertEquals("xz", (String) d12.invokeExact("x", 12, true, "z"));
+            }}
+    }
+
     @Test public void testDropArguments() throws Throwable {
         {{
 {} /// JAVADOC
@@ -145,6 +200,21 @@
             }}
     }
 
+    @Test public void testFoldArguments() throws Throwable {
+        {{
+{} /// JAVADOC
+MethodHandle trace = publicLookup().findVirtual(java.io.PrintStream.class,
+  "println", methodType(void.class, String.class))
+    .bindTo(System.out);
+MethodHandle cat = lookup().findVirtual(String.class,
+  "concat", methodType(String.class, String.class));
+assertEquals("boojum", (String) cat.invokeExact("boo", "jum"));
+MethodHandle catTrace = foldArguments(cat, trace);
+// also prints "boo":
+assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
+            }}
+    }
+
     static void assertEquals(Object exp, Object act) {
         if (verbosity > 0)
             System.out.println("result: "+act);
@@ -162,24 +232,24 @@
 mh = lookup.findVirtual(String.class, "replace", mt);
 s = (String) mh.invokeExact("daddy",'d','n');
 // invokeExact(Ljava/lang/String;CC)Ljava/lang/String;
-assert(s.equals("nanny"));
+assertEquals(s, "nanny");
 // weakly typed invocation (using MHs.invoke)
 s = (String) mh.invokeWithArguments("sappy", 'p', 'v');
-assert(s.equals("savvy"));
+assertEquals(s, "savvy");
 // mt is (Object[])List
 mt = MethodType.methodType(java.util.List.class, Object[].class);
 mh = lookup.findStatic(java.util.Arrays.class, "asList", mt);
 assert(mh.isVarargsCollector());
 x = mh.invoke("one", "two");
 // invoke(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;
-assert(x.equals(java.util.Arrays.asList("one","two")));
+assertEquals(x, java.util.Arrays.asList("one","two"));
 // mt is (Object,Object,Object)Object
 mt = MethodType.genericMethodType(3);
 mh = mh.asType(mt);
 x = mh.invokeExact((Object)1, (Object)2, (Object)3);
 // invokeExact(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
-assert(x.equals(java.util.Arrays.asList(1,2,3)));
-// mt is { =&gt; int}
+assertEquals(x, java.util.Arrays.asList(1,2,3));
+// mt is ()int
 mt = MethodType.methodType(int.class);
 mh = lookup.findVirtual(java.util.List.class, "size", mt);
 i = (int) mh.invokeExact(java.util.Arrays.asList(1,2,3));
@@ -193,37 +263,239 @@
             }}
     }
 
+    @Test public void testAsSpreader() throws Throwable {
+        {{
+{} /// JAVADOC
+MethodHandle equals = publicLookup()
+  .findVirtual(String.class, "equals", methodType(boolean.class, Object.class));
+assert( (boolean) equals.invokeExact("me", (Object)"me"));
+assert(!(boolean) equals.invokeExact("me", (Object)"thee"));
+// spread both arguments from a 2-array:
+MethodHandle eq2 = equals.asSpreader(Object[].class, 2);
+assert( (boolean) eq2.invokeExact(new Object[]{ "me", "me" }));
+assert(!(boolean) eq2.invokeExact(new Object[]{ "me", "thee" }));
+// spread both arguments from a String array:
+MethodHandle eq2s = equals.asSpreader(String[].class, 2);
+assert( (boolean) eq2s.invokeExact(new String[]{ "me", "me" }));
+assert(!(boolean) eq2s.invokeExact(new String[]{ "me", "thee" }));
+// spread second arguments from a 1-array:
+MethodHandle eq1 = equals.asSpreader(Object[].class, 1);
+assert( (boolean) eq1.invokeExact("me", new Object[]{ "me" }));
+assert(!(boolean) eq1.invokeExact("me", new Object[]{ "thee" }));
+// spread no arguments from a 0-array or null:
+MethodHandle eq0 = equals.asSpreader(Object[].class, 0);
+assert( (boolean) eq0.invokeExact("me", (Object)"me", new Object[0]));
+assert(!(boolean) eq0.invokeExact("me", (Object)"thee", (Object[])null));
+// asSpreader and asCollector are approximate inverses:
+for (int n = 0; n <= 2; n++) {
+    for (Class<?> a : new Class<?>[]{Object[].class, String[].class, CharSequence[].class}) {
+        MethodHandle equals2 = equals.asSpreader(a, n).asCollector(a, n);
+        assert( (boolean) equals2.invokeWithArguments("me", "me"));
+        assert(!(boolean) equals2.invokeWithArguments("me", "thee"));
+    }
+}
+MethodHandle caToString = publicLookup()
+  .findStatic(Arrays.class, "toString", methodType(String.class, char[].class));
+assertEquals("[A, B, C]", (String) caToString.invokeExact("ABC".toCharArray()));
+MethodHandle caString3 = caToString.asCollector(char[].class, 3);
+assertEquals("[A, B, C]", (String) caString3.invokeExact('A', 'B', 'C'));
+MethodHandle caToString2 = caString3.asSpreader(char[].class, 2);
+assertEquals("[A, B, C]", (String) caToString2.invokeExact('A', "BC".toCharArray()));
+            }}
+    }
+
+    @Test public void testAsCollector() throws Throwable {
+        {{
+{} /// JAVADOC
+MethodHandle deepToString = publicLookup()
+  .findStatic(Arrays.class, "deepToString", methodType(String.class, Object[].class));
+assertEquals("[won]",   (String) deepToString.invokeExact(new Object[]{"won"}));
+MethodHandle ts1 = deepToString.asCollector(Object[].class, 1);
+assertEquals(methodType(String.class, Object.class), ts1.type());
+//assertEquals("[won]", (String) ts1.invokeExact(         new Object[]{"won"})); //FAIL
+assertEquals("[[won]]", (String) ts1.invokeExact((Object) new Object[]{"won"}));
+// arrayType can be a subtype of Object[]
+MethodHandle ts2 = deepToString.asCollector(String[].class, 2);
+assertEquals(methodType(String.class, String.class, String.class), ts2.type());
+assertEquals("[two, too]", (String) ts2.invokeExact("two", "too"));
+MethodHandle ts0 = deepToString.asCollector(Object[].class, 0);
+assertEquals("[]", (String) ts0.invokeExact());
+// collectors can be nested, Lisp-style
+MethodHandle ts22 = deepToString.asCollector(Object[].class, 3).asCollector(String[].class, 2);
+assertEquals("[A, B, [C, D]]", ((String) ts22.invokeExact((Object)'A', (Object)"B", "C", "D")));
+// arrayType can be any primitive array type
+MethodHandle bytesToString = publicLookup()
+  .findStatic(Arrays.class, "toString", methodType(String.class, byte[].class))
+  .asCollector(byte[].class, 3);
+assertEquals("[1, 2, 3]", (String) bytesToString.invokeExact((byte)1, (byte)2, (byte)3));
+MethodHandle longsToString = publicLookup()
+  .findStatic(Arrays.class, "toString", methodType(String.class, long[].class))
+  .asCollector(long[].class, 1);
+assertEquals("[123]", (String) longsToString.invokeExact((long)123));
+            }}
+    }
+
     @Test public void testAsVarargsCollector() throws Throwable {
         {{
 {} /// JAVADOC
+MethodHandle deepToString = publicLookup()
+  .findStatic(Arrays.class, "deepToString", methodType(String.class, Object[].class));
+MethodHandle ts1 = deepToString.asVarargsCollector(Object[].class);
+assertEquals("[won]",   (String) ts1.invokeExact(    new Object[]{"won"}));
+assertEquals("[won]",   (String) ts1.invoke(         new Object[]{"won"}));
+assertEquals("[won]",   (String) ts1.invoke(                      "won" ));
+assertEquals("[[won]]", (String) ts1.invoke((Object) new Object[]{"won"}));
+// findStatic of Arrays.asList(...) produces a variable arity method handle:
 MethodHandle asList = publicLookup()
-  .findStatic(Arrays.class, "asList", methodType(List.class, Object[].class))
-  .asVarargsCollector(Object[].class);
+  .findStatic(Arrays.class, "asList", methodType(List.class, Object[].class));
+assertEquals(methodType(List.class, Object[].class), asList.type());
+assert(asList.isVarargsCollector());
 assertEquals("[]", asList.invoke().toString());
 assertEquals("[1]", asList.invoke(1).toString());
 assertEquals("[two, too]", asList.invoke("two", "too").toString());
-Object[] argv = { "three", "thee", "tee" };
+String[] argv = { "three", "thee", "tee" };
 assertEquals("[three, thee, tee]", asList.invoke(argv).toString());
+assertEquals("[three, thee, tee]", asList.invoke((Object[])argv).toString());
 List ls = (List) asList.invoke((Object)argv);
 assertEquals(1, ls.size());
 assertEquals("[three, thee, tee]", Arrays.toString((Object[])ls.get(0)));
             }}
     }
 
-    @Test public void testVarargsCollectorSuppression() throws Throwable {
+    @Test public void testAsFixedArity() throws Throwable {
         {{
 {} /// JAVADOC
-MethodHandle vamh = publicLookup()
+MethodHandle asListVar = publicLookup()
   .findStatic(Arrays.class, "asList", methodType(List.class, Object[].class))
   .asVarargsCollector(Object[].class);
-MethodHandle mh = MethodHandles.exactInvoker(vamh.type()).bindTo(vamh);
-assert(vamh.type().equals(mh.type()));
-assertEquals("[1, 2, 3]", vamh.invoke(1,2,3).toString());
-boolean failed = false;
-try { mh.invoke(1,2,3); }
-catch (WrongMethodTypeException ex) { failed = true; }
-assert(failed);
+MethodHandle asListFix = asListVar.asFixedArity();
+assertEquals("[1]", asListVar.invoke(1).toString());
+Exception caught = null;
+try { asListFix.invoke((Object)1); }
+catch (Exception ex) { caught = ex; }
+assert(caught instanceof ClassCastException);
+assertEquals("[two, too]", asListVar.invoke("two", "too").toString());
+try { asListFix.invoke("two", "too"); }
+catch (Exception ex) { caught = ex; }
+assert(caught instanceof WrongMethodTypeException);
+Object[] argv = { "three", "thee", "tee" };
+assertEquals("[three, thee, tee]", asListVar.invoke(argv).toString());
+assertEquals("[three, thee, tee]", asListFix.invoke(argv).toString());
+assertEquals(1, ((List) asListVar.invoke((Object)argv)).size());
+assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString());
+            }}
+    }
+
+    @Test public void testAsTypeCornerCases() throws Throwable {
+        {{
+{} /// JAVADOC
+MethodHandle i2s = publicLookup()
+  .findVirtual(Integer.class, "toString", methodType(String.class));
+i2s = i2s.asType(i2s.type().unwrap());
+MethodHandle l2s = publicLookup()
+  .findVirtual(Long.class, "toString", methodType(String.class));
+l2s = l2s.asType(l2s.type().unwrap());
+
+Exception caught = null;
+try { i2s.asType(methodType(String.class, String.class)); }
+catch (Exception ex) { caught = ex; }
+assert(caught instanceof WrongMethodTypeException);
+
+i2s.asType(methodType(String.class, byte.class));
+i2s.asType(methodType(String.class, Byte.class));
+i2s.asType(methodType(String.class, Character.class));
+i2s.asType(methodType(String.class, Integer.class));
+l2s.asType(methodType(String.class, byte.class));
+l2s.asType(methodType(String.class, Byte.class));
+l2s.asType(methodType(String.class, Character.class));
+l2s.asType(methodType(String.class, Integer.class));
+l2s.asType(methodType(String.class, Long.class));
+
+caught = null;
+try { i2s.asType(methodType(String.class, Long.class)); }
+catch (Exception ex) { caught = ex; }
+assert(caught instanceof WrongMethodTypeException);
+
+MethodHandle i2sGen = i2s.asType(methodType(String.class, Object.class));
+MethodHandle l2sGen = l2s.asType(methodType(String.class, Object.class));
+
+i2sGen.invoke(42);  // int -> Integer -> Object -> Integer -> int
+i2sGen.invoke((byte)4);  // byte -> Byte -> Object -> Byte -> byte -> int
+l2sGen.invoke(42);  // int -> Integer -> Object -> Integer -> int
+l2sGen.invoke((byte)4);  // byte -> Byte -> Object -> Byte -> byte -> int
+l2sGen.invoke(0x420000000L);
+
+caught = null;
+try { i2sGen.invoke(0x420000000L); } // long -> Long -> Object -> Integer CCE
+catch (Exception ex) { caught = ex; }
+assert(caught instanceof ClassCastException);
+
+caught = null;
+try { i2sGen.invoke("asdf"); } // String -> Object -> Integer CCE
+catch (Exception ex) { caught = ex; }
+assert(caught instanceof ClassCastException);
 {}
             }}
     }
+
+    @Test public void testMutableCallSite() throws Throwable {
+        {{
+{} /// JAVADOC
+MutableCallSite name = new MutableCallSite(MethodType.methodType(String.class));
+MethodHandle MH_name = name.dynamicInvoker();
+MethodType MT_str1 = MethodType.methodType(String.class);
+MethodHandle MH_upcase = MethodHandles.lookup()
+    .findVirtual(String.class, "toUpperCase", MT_str1);
+MethodHandle worker1 = MethodHandles.filterReturnValue(MH_name, MH_upcase);
+name.setTarget(MethodHandles.constant(String.class, "Rocky"));
+assertEquals("ROCKY", (String) worker1.invokeExact());
+name.setTarget(MethodHandles.constant(String.class, "Fred"));
+assertEquals("FRED", (String) worker1.invokeExact());
+// (mutation can be continued indefinitely)
+/*
+ * </pre></blockquote>
+ * <p>
+ * The same call site may be used in several places at once.
+ * <blockquote><pre>
+ */
+MethodType MT_str2 = MethodType.methodType(String.class, String.class);
+MethodHandle MH_cat = lookup().findVirtual(String.class,
+  "concat", methodType(String.class, String.class));
+MethodHandle MH_dear = MethodHandles.insertArguments(MH_cat, 1, ", dear?");
+MethodHandle worker2 = MethodHandles.filterReturnValue(MH_name, MH_dear);
+assertEquals("Fred, dear?", (String) worker2.invokeExact());
+name.setTarget(MethodHandles.constant(String.class, "Wilma"));
+assertEquals("WILMA", (String) worker1.invokeExact());
+assertEquals("Wilma, dear?", (String) worker2.invokeExact());
+{}
+            }}
+    }
+
+    @Test public void testSwitchPoint() throws Throwable {
+        {{
+{} /// JAVADOC
+MethodHandle MH_strcat = MethodHandles.lookup()
+    .findVirtual(String.class, "concat", MethodType.methodType(String.class, String.class));
+SwitchPoint spt = new SwitchPoint();
+assert(spt.isValid());
+// the following steps may be repeated to re-use the same switch point:
+MethodHandle worker1 = MH_strcat;
+MethodHandle worker2 = MethodHandles.permuteArguments(MH_strcat, MH_strcat.type(), 1, 0);
+MethodHandle worker = spt.guardWithTest(worker1, worker2);
+assertEquals("method", (String) worker.invokeExact("met", "hod"));
+SwitchPoint.invalidateAll(new SwitchPoint[]{ spt });
+assert(!spt.isValid());
+assertEquals("hodmet", (String) worker.invokeExact("met", "hod"));
+{}
+            }}
+    }
+
+    /* ---- TEMPLATE ----
+    @Test public void testFoo() throws Throwable {
+        {{
+{} /// JAVADOC
+{}
+            }}
+    }
+    */
 }
--- a/jdk/test/java/lang/invoke/MethodHandlesTest.java	Thu May 26 20:20:03 2011 -0700
+++ b/jdk/test/java/lang/invoke/MethodHandlesTest.java	Fri May 27 19:03:03 2011 -0700
@@ -100,6 +100,31 @@
         // ValueConversions.varargsArray: UnsupportedOperationException: NYI: cannot form a varargs array of length 13
         testInsertArguments(0, 0, MAX_ARG_INCREASE+10);
     }
+    @Test @Ignore("permuteArguments has trouble with double slots")
+    public void testFail_7() throws Throwable {
+        testPermuteArguments(new Object[]{10, 200L},
+                             new Class<?>[]{Integer.class, long.class},
+                             new int[]{1,0});
+        testPermuteArguments(new Object[]{10, 200L, 5000L},
+                             new Class<?>[]{Integer.class, long.class, long.class},
+                             new int[]{2,0,1}); //rot
+        testPermuteArguments(new Object[]{10, 200L, 5000L},
+                             new Class<?>[]{Integer.class, long.class, long.class},
+                             new int[]{1,2,0}); //rot
+        testPermuteArguments(new Object[]{10, 200L, 5000L},
+                             new Class<?>[]{Integer.class, long.class, long.class},
+                             new int[]{2,1,0}); //swap
+        testPermuteArguments(new Object[]{10, 200L, 5000L},
+                             new Class<?>[]{Integer.class, long.class, long.class},
+                             new int[]{0,1,2,2}); //dup
+        testPermuteArguments(new Object[]{10, 200L, 5000L},
+                             new Class<?>[]{Integer.class, long.class, long.class},
+                             new int[]{2,0,1,2});
+        testPermuteArguments(new Object[]{10, 200L, 5000L},
+                             new Class<?>[]{Integer.class, long.class, long.class},
+                             new int[]{2,2,0,1});
+        testPermuteArguments(4, Integer.class,  2, long.class,    6);
+    }
     static final int MAX_ARG_INCREASE = 3;
 
     public MethodHandlesTest() {
@@ -356,7 +381,7 @@
         ArrayList<Class<?>> argTypes = new ArrayList<Class<?>>(targetType.parameterList());
         Collections.fill(argTypes.subList(beg, end), argType);
         MethodType ttype2 = MethodType.methodType(targetType.returnType(), argTypes);
-        return MethodHandles.convertArguments(target, ttype2);
+        return target.asType(ttype2);
     }
 
     // This lookup is good for all members in and under MethodHandlesTest.
@@ -1005,13 +1030,13 @@
         Class<?> vtype = ftype;
         if (ftype != int.class)  vtype = Object.class;
         if (isGetter) {
-            mh = MethodHandles.convertArguments(mh, mh.type().generic()
-                                                .changeReturnType(vtype));
+            mh = mh.asType(mh.type().generic()
+                           .changeReturnType(vtype));
         } else {
             int last = mh.type().parameterCount() - 1;
-            mh = MethodHandles.convertArguments(mh, mh.type().generic()
-                                                .changeReturnType(void.class)
-                                                .changeParameterType(last, vtype));
+            mh = mh.asType(mh.type().generic()
+                           .changeReturnType(void.class)
+                           .changeParameterType(last, vtype));
         }
         if (f != null && f.getDeclaringClass() == HasFields.class) {
             assertEquals(f.get(fields), value);  // clean to start with
@@ -1139,7 +1164,7 @@
             // FIXME: change Integer.class and (Integer) below to int.class and (int) below.
             MethodType gtype = mh.type().generic().changeParameterType(1, Integer.class);
             if (testSetter)  gtype = gtype.changeReturnType(void.class);
-            mh = MethodHandles.convertArguments(mh, gtype);
+            mh = mh.asType(gtype);
         }
         Object sawValue, expValue;
         List<Object> model = array2list(array);
@@ -1233,11 +1258,10 @@
     }
 
     void testConvert(MethodHandle id, Class<?> rtype, String name, Class<?>... params) throws Throwable {
-        testConvert(true, false, id, rtype, name, params);
-        testConvert(true, true,  id, rtype, name, params);
+        testConvert(true, id, rtype, name, params);
     }
 
-    void testConvert(boolean positive, boolean useAsType,
+    void testConvert(boolean positive,
                      MethodHandle id, Class<?> rtype, String name, Class<?>... params) throws Throwable {
         countTest(positive);
         MethodType idType = id.type();
@@ -1265,10 +1289,7 @@
         MethodHandle target = null;
         RuntimeException error = null;
         try {
-            if (useAsType)
-                target = id.asType(newType);
-            else
-                target = MethodHandles.convertArguments(id, newType);
+            target = id.asType(newType);
         } catch (RuntimeException ex) {
             error = ex;
         }
@@ -1293,11 +1314,11 @@
                                MethodType.methodType(Object.class, String.class, Object[].class));
         vac0 = vac0.bindTo("vac");
         MethodHandle vac = vac0.asVarargsCollector(Object[].class);
-        testConvert(true,  true,  vac.asType(MethodType.genericMethodType(0)), null, "vac");
-        testConvert(true,  true,  vac.asType(MethodType.genericMethodType(0)), null, "vac");
+        testConvert(true, vac.asType(MethodType.genericMethodType(0)), null, "vac");
+        testConvert(true, vac.asType(MethodType.genericMethodType(0)), null, "vac");
         for (Class<?> at : new Class[] { Object.class, String.class, Integer.class }) {
-            testConvert(true,  true,  vac.asType(MethodType.genericMethodType(1)), null, "vac", at);
-            testConvert(true,  true,  vac.asType(MethodType.genericMethodType(2)), null, "vac", at, at);
+            testConvert(true, vac.asType(MethodType.genericMethodType(1)), null, "vac", at);
+            testConvert(true, vac.asType(MethodType.genericMethodType(2)), null, "vac", at, at);
         }
     }
 
@@ -1306,8 +1327,8 @@
         if (CAN_SKIP_WORKING)  return;
         startTest("permuteArguments");
         testPermuteArguments(4, Integer.class,  2, String.class,  0);
-        //testPermuteArguments(6, Integer.class,  0, null,         30);
-        //testPermuteArguments(4, Integer.class,  1, int.class,     6);
+        testPermuteArguments(6, Integer.class,  0, null,         30);
+        //testPermuteArguments(4, Integer.class,  2, long.class,    6);  // FIXME Fail_7
     }
     public void testPermuteArguments(int max, Class<?> type1, int t2c, Class<?> type2, int dilution) throws Throwable {
         if (verbosity >= 2)
@@ -1421,8 +1442,9 @@
         }
         MethodType inType  = MethodType.methodType(Object.class, types);
         MethodType outType = MethodType.methodType(Object.class, permTypes);
-        MethodHandle target = MethodHandles.convertArguments(varargsList(outargs), outType);
+        MethodHandle target = varargsList(outargs).asType(outType);
         MethodHandle newTarget = MethodHandles.permuteArguments(target, inType, reorder);
+        if (verbosity >= 5)  System.out.println("newTarget = "+newTarget);
         Object result = newTarget.invokeWithArguments(args);
         Object expected = Arrays.asList(permArgs);
         if (!expected.equals(result)) {
@@ -1666,7 +1688,7 @@
         countTest();
         MethodHandle target = varargsList(nargs);
         MethodHandle filter = varargsList(1);
-        filter = MethodHandles.convertArguments(filter, filter.type().generic());
+        filter = filter.asType(filter.type().generic());
         Object[] argsToPass = randomArgs(nargs, Object.class);
         if (verbosity >= 3)
             System.out.println("filter "+target+" at "+pos+" with "+filter);
@@ -1807,7 +1829,7 @@
         // generic invoker
         countTest();
         inv = MethodHandles.invoker(type);
-        if (nargs <= 3) {
+        if (nargs <= 3 && type == type.generic()) {
             calledLog.clear();
             switch (nargs) {
             case 0:
@@ -1833,10 +1855,16 @@
         // varargs invoker #0
         calledLog.clear();
         inv = MethodHandles.spreadInvoker(type, 0);
-        result = inv.invokeExact(target, args);
+        if (type.returnType() == Object.class) {
+            result = inv.invokeExact(target, args);
+        } else if (type.returnType() == void.class) {
+            result = null; inv.invokeExact(target, args);
+        } else {
+            result = inv.invokeWithArguments(target, (Object) args);
+        }
         if (testRetCode)  assertEquals(code, result);
         assertCalled("invokee", args);
-        if (nargs >= 1) {
+        if (nargs >= 1 && type == type.generic()) {
             // varargs invoker #1
             calledLog.clear();
             inv = MethodHandles.spreadInvoker(type, 1);
@@ -1844,7 +1872,7 @@
             if (testRetCode)  assertEquals(code, result);
             assertCalled("invokee", args);
         }
-        if (nargs >= 2) {
+        if (nargs >= 2 && type == type.generic()) {
             // varargs invoker #2
             calledLog.clear();
             inv = MethodHandles.spreadInvoker(type, 2);
@@ -1852,7 +1880,7 @@
             if (testRetCode)  assertEquals(code, result);
             assertCalled("invokee", args);
         }
-        if (nargs >= 3) {
+        if (nargs >= 3 && type == type.generic()) {
             // varargs invoker #3
             calledLog.clear();
             inv = MethodHandles.spreadInvoker(type, 3);
@@ -1865,6 +1893,10 @@
             countTest();
             calledLog.clear();
             inv = MethodHandles.spreadInvoker(type, k);
+            MethodType expType = (type.dropParameterTypes(k, nargs)
+                                  .appendParameterTypes(Object[].class)
+                                  .insertParameterTypes(0, MethodHandle.class));
+            assertEquals(expType, inv.type());
             List<Object> targetPlusVarArgs = new ArrayList<Object>(targetPlusArgs);
             List<Object> tailList = targetPlusVarArgs.subList(1+k, 1+nargs);
             Object[] tail = tailList.toArray();
@@ -2045,7 +2077,7 @@
         //System.out.println("throwing with "+target+" : "+thrown);
         MethodType expectedType = MethodType.methodType(returnType, exType);
         assertEquals(expectedType, target.type());
-        target = MethodHandles.convertArguments(target, target.type().generic());
+        target = target.asType(target.type().generic());
         Throwable caught = null;
         try {
             Object res = target.invokeExact((Object) thrown);
@@ -2117,12 +2149,12 @@
         if (mode.endsWith("/return")) {
             if (mode.equals("unbox/return")) {
                 // fail on return to ((Integer)surprise).intValue
-                surprise = MethodHandles.convertArguments(surprise, MethodType.methodType(int.class, Object.class));
-                identity = MethodHandles.convertArguments(identity, MethodType.methodType(int.class, Object.class));
+                surprise = surprise.asType(MethodType.methodType(int.class, Object.class));
+                identity = identity.asType(MethodType.methodType(int.class, Object.class));
             } else if (mode.equals("cast/return")) {
                 // fail on return to (Integer)surprise
-                surprise = MethodHandles.convertArguments(surprise, MethodType.methodType(Integer.class, Object.class));
-                identity = MethodHandles.convertArguments(identity, MethodType.methodType(Integer.class, Object.class));
+                surprise = surprise.asType(MethodType.methodType(Integer.class, Object.class));
+                identity = identity.asType(MethodType.methodType(Integer.class, Object.class));
             }
         } else if (mode.endsWith("/argument")) {
             MethodHandle callee = null;
@@ -2134,14 +2166,14 @@
                 callee = Surprise.BOX_IDENTITY;
             }
             if (callee != null) {
-                callee = MethodHandles.convertArguments(callee, MethodType.genericMethodType(1));
+                callee = callee.asType(MethodType.genericMethodType(1));
                 surprise = MethodHandles.filterArguments(callee, 0, surprise);
                 identity = MethodHandles.filterArguments(callee, 0, identity);
             }
         }
         assertNotSame(mode, surprise, surprise0);
-        identity = MethodHandles.convertArguments(identity, MethodType.genericMethodType(1));
-        surprise = MethodHandles.convertArguments(surprise, MethodType.genericMethodType(1));
+        identity = identity.asType(MethodType.genericMethodType(1));
+        surprise = surprise.asType(MethodType.genericMethodType(1));
         Object x = 42;
         for (int i = 0; i < okCount; i++) {
             Object y = identity.invokeExact(x);
@@ -2230,14 +2262,14 @@
         {
             MethodType mt = MethodType.methodType(void.class);
             MethodHandle mh = lookup.findStatic(MethodHandlesTest.class, "runForRunnable", mt);
-            Runnable proxy = MethodHandles.asInstance(mh, Runnable.class);
+            Runnable proxy = MethodHandleProxies.asInterfaceInstance(Runnable.class, mh);
             proxy.run();
             assertCalled("runForRunnable");
         }
         {
             MethodType mt = MethodType.methodType(Object.class, Fooable.class, Object.class);
             MethodHandle mh = lookup.findStatic(MethodHandlesTest.class, "fooForFooable", mt);
-            Fooable proxy = MethodHandles.asInstance(mh, Fooable.class);
+            Fooable proxy = MethodHandleProxies.asInterfaceInstance(Fooable.class, mh);
             Object[] args = randomArgs(mt.parameterArray());
             Object result = proxy.foo((Fooable) args[0], args[1]);
             assertCalled("fooForFooable", args);
@@ -2251,7 +2283,7 @@
                                             }) {
             MethodHandle mh = MethodHandles.throwException(void.class, Throwable.class);
             mh = MethodHandles.insertArguments(mh, 0, ex);
-            WillThrow proxy = MethodHandles.asInstance(mh, WillThrow.class);
+            WillThrow proxy = MethodHandleProxies.asInterfaceInstance(WillThrow.class, mh);
             try {
                 proxy.willThrow();
                 System.out.println("Failed to throw: "+ex);
@@ -2279,7 +2311,7 @@
                                              CharSequence.class,
                                              Example.class }) {
             try {
-                MethodHandles.asInstance(varargsArray(0), nonSAM);
+                MethodHandleProxies.asInterfaceInstance(nonSAM, varargsArray(0));
                 System.out.println("Failed to throw");
                 assertTrue(false);
             } catch (IllegalArgumentException ex) {
--- a/jdk/test/java/lang/invoke/indify/Indify.java	Thu May 26 20:20:03 2011 -0700
+++ b/jdk/test/java/lang/invoke/indify/Indify.java	Fri May 27 19:03:03 2011 -0700
@@ -524,6 +524,8 @@
             if (verifySpecifierCount >= 0) {
                 List<Object[]> specs = bootstrapMethodSpecifiers(false);
                 int specsLen = (specs == null ? 0 : specs.size());
+                // Pass by specsLen == 0, to help with associated (inner) classes.
+                if (specsLen == 0)  specsLen = verifySpecifierCount;
                 if (specsLen != verifySpecifierCount) {
                     throw new IllegalArgumentException("BootstrapMethods length is "+specsLen+" but should be "+verifySpecifierCount);
                 }