jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java
changeset 9646 5ebbe5ab084f
parent 8822 8145ab9f5f86
child 9730 e4b334d47f4b
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java	Thu May 12 19:27:33 2011 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java	Thu May 12 19:27:49 2011 -0700
@@ -121,11 +121,11 @@
             if (nargs < INVOKES.length) {
                 MethodHandle invoke = INVOKES[nargs];
                 MethodType conType = CON_TYPES[nargs];
-                MethodHandle gcon = convertArguments(rawConstructor, conType, rawConType, null);
+                MethodHandle gcon = convertArguments(rawConstructor, conType, rawConType, 0);
                 if (gcon == null)  return null;
                 MethodHandle galloc = new AllocateObject(invoke, allocateClass, gcon);
                 assert(galloc.type() == newType.generic());
-                return convertArguments(galloc, newType, galloc.type(), null);
+                return convertArguments(galloc, newType, galloc.type(), 0);
             } else {
                 MethodHandle invoke = VARARGS_INVOKE;
                 MethodType conType = CON_TYPES[nargs];
@@ -256,8 +256,8 @@
                 FieldAccessor.ahandle(arrayClass, true)
             };
             if (mhs[0].type().parameterType(0) == Class.class) {
-                mhs[0] = MethodHandles.insertArguments(mhs[0], 0, elemClass);
-                mhs[1] = MethodHandles.insertArguments(mhs[1], 0, elemClass);
+                mhs[0] = mhs[0].bindTo(elemClass);
+                mhs[1] = mhs[1].bindTo(elemClass);
             }
             synchronized (FieldAccessor.ARRAY_CACHE) {}  // memory barrier
             FieldAccessor.ARRAY_CACHE.put(elemClass, mhs);
@@ -372,7 +372,7 @@
             if (evclass != vclass || (!isStatic && ecclass != cclass)) {
                 MethodType strongType = FieldAccessor.ftype(cclass, vclass, isSetter, isStatic);
                 strongType = strongType.insertParameterTypes(0, FieldAccessor.class);
-                mh = MethodHandles.convertArguments(mh, strongType);
+                mh = convertArguments(mh, strongType, 0);
             }
             return mh;
         }
@@ -439,8 +439,8 @@
             }
             if (caclass != null) {
                 MethodType strongType = FieldAccessor.atype(caclass, isSetter);
-                mh = MethodHandles.insertArguments(mh, 0, caclass);
-                mh = MethodHandles.convertArguments(mh, strongType);
+                mh = mh.bindTo(caclass);
+                mh = convertArguments(mh, strongType, 0);
             }
             return mh;
         }
@@ -465,7 +465,7 @@
                     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(), null);
+                    return convertArguments(bmh, newType, bmh.type(), 0);
                 }
             }
         }
@@ -486,301 +486,378 @@
         return new BoundMethodHandle(target, receiver, argnum);
     }
 
-    static MethodHandle convertArguments(MethodHandle target,
+    static MethodHandle permuteArguments(MethodHandle target,
                                                 MethodType newType,
                                                 MethodType oldType,
                                                 int[] permutationOrNull) {
         assert(oldType.parameterCount() == target.type().parameterCount());
-        if (permutationOrNull != null) {
-            int outargs = oldType.parameterCount(), inargs = newType.parameterCount();
-            if (permutationOrNull.length != outargs)
-                throw newIllegalArgumentException("wrong number of arguments in permutation");
-            // Make the individual outgoing argument types match up first.
-            Class<?>[] callTypeArgs = new Class<?>[outargs];
-            for (int i = 0; i < outargs; i++)
-                callTypeArgs[i] = newType.parameterType(permutationOrNull[i]);
-            MethodType callType = MethodType.methodType(oldType.returnType(), callTypeArgs);
-            target = convertArguments(target, callType, oldType, null);
-            assert(target != null);
-            oldType = target.type();
-            List<Integer> goal = new ArrayList<Integer>();  // i*TOKEN
-            List<Integer> state = new ArrayList<Integer>(); // i*TOKEN
-            List<Integer> drops = new ArrayList<Integer>(); // not tokens
-            List<Integer> dups = new ArrayList<Integer>();  // not tokens
-            final int TOKEN = 10; // to mark items which are symbolic only
-            // state represents the argument values coming into target
-            for (int i = 0; i < outargs; i++) {
-                state.add(permutationOrNull[i] * TOKEN);
+        int outargs = oldType.parameterCount(), inargs = newType.parameterCount();
+        if (permutationOrNull.length != outargs)
+            throw newIllegalArgumentException("wrong number of arguments in permutation");
+        // Make the individual outgoing argument types match up first.
+        Class<?>[] callTypeArgs = new Class<?>[outargs];
+        for (int i = 0; i < outargs; i++)
+            callTypeArgs[i] = newType.parameterType(permutationOrNull[i]);
+        MethodType callType = MethodType.methodType(oldType.returnType(), callTypeArgs);
+        target = convertArguments(target, callType, oldType, 0);
+        assert(target != null);
+        oldType = target.type();
+        List<Integer> goal = new ArrayList<Integer>();  // i*TOKEN
+        List<Integer> state = new ArrayList<Integer>(); // i*TOKEN
+        List<Integer> drops = new ArrayList<Integer>(); // not tokens
+        List<Integer> dups = new ArrayList<Integer>();  // not tokens
+        final int TOKEN = 10; // to mark items which are symbolic only
+        // state represents the argument values coming into target
+        for (int i = 0; i < outargs; i++) {
+            state.add(permutationOrNull[i] * TOKEN);
+        }
+        // goal represents the desired state
+        for (int i = 0; i < inargs; i++) {
+            if (state.contains(i * TOKEN)) {
+                goal.add(i * TOKEN);
+            } else {
+                // adapter must initially drop all unused arguments
+                drops.add(i);
             }
-            // goal represents the desired state
-            for (int i = 0; i < inargs; i++) {
-                if (state.contains(i * TOKEN)) {
-                    goal.add(i * TOKEN);
-                } else {
-                    // adapter must initially drop all unused arguments
-                    drops.add(i);
+        }
+        // detect duplications
+        while (state.size() > goal.size()) {
+            for (int i2 = 0; i2 < state.size(); i2++) {
+                int arg1 = state.get(i2);
+                int i1 = state.indexOf(arg1);
+                if (i1 != i2) {
+                    // found duplicate occurrence at i2
+                    int arg2 = (inargs++) * TOKEN;
+                    state.set(i2, arg2);
+                    dups.add(goal.indexOf(arg1));
+                    goal.add(arg2);
                 }
             }
-            // detect duplications
-            while (state.size() > goal.size()) {
-                for (int i2 = 0; i2 < state.size(); i2++) {
-                    int arg1 = state.get(i2);
-                    int i1 = state.indexOf(arg1);
-                    if (i1 != i2) {
-                        // found duplicate occurrence at i2
-                        int arg2 = (inargs++) * TOKEN;
-                        state.set(i2, arg2);
-                        dups.add(goal.indexOf(arg1));
-                        goal.add(arg2);
+        }
+        assert(state.size() == goal.size());
+        int size = goal.size();
+        while (!state.equals(goal)) {
+            // Look for a maximal sequence of adjacent misplaced arguments,
+            // and try to rotate them into place.
+            int bestRotArg = -10 * TOKEN, bestRotLen = 0;
+            int thisRotArg = -10 * TOKEN, thisRotLen = 0;
+            for (int i = 0; i < size; i++) {
+                int arg = state.get(i);
+                // Does this argument match the current run?
+                if (arg == thisRotArg + TOKEN) {
+                    thisRotArg = arg;
+                    thisRotLen += 1;
+                    if (bestRotLen < thisRotLen) {
+                        bestRotLen = thisRotLen;
+                        bestRotArg = thisRotArg;
+                    }
+                } else {
+                    // The old sequence (if any) stops here.
+                    thisRotLen = 0;
+                    thisRotArg = -10 * TOKEN;
+                    // But maybe a new one starts here also.
+                    int wantArg = goal.get(i);
+                    final int MAX_ARG_ROTATION = AdapterMethodHandle.MAX_ARG_ROTATION;
+                    if (arg != wantArg &&
+                        arg >= wantArg - TOKEN * MAX_ARG_ROTATION &&
+                        arg <= wantArg + TOKEN * MAX_ARG_ROTATION) {
+                        thisRotArg = arg;
+                        thisRotLen = 1;
                     }
                 }
             }
-            assert(state.size() == goal.size());
-            int size = goal.size();
-            while (!state.equals(goal)) {
-                // Look for a maximal sequence of adjacent misplaced arguments,
-                // and try to rotate them into place.
-                int bestRotArg = -10 * TOKEN, bestRotLen = 0;
-                int thisRotArg = -10 * TOKEN, thisRotLen = 0;
-                for (int i = 0; i < size; i++) {
-                    int arg = state.get(i);
-                    // Does this argument match the current run?
-                    if (arg == thisRotArg + TOKEN) {
-                        thisRotArg = arg;
-                        thisRotLen += 1;
-                        if (bestRotLen < thisRotLen) {
-                            bestRotLen = thisRotLen;
-                            bestRotArg = thisRotArg;
-                        }
-                    } else {
-                        // The old sequence (if any) stops here.
-                        thisRotLen = 0;
-                        thisRotArg = -10 * TOKEN;
-                        // But maybe a new one starts here also.
-                        int wantArg = goal.get(i);
-                        final int MAX_ARG_ROTATION = AdapterMethodHandle.MAX_ARG_ROTATION;
-                        if (arg != wantArg &&
-                            arg >= wantArg - TOKEN * MAX_ARG_ROTATION &&
-                            arg <= wantArg + TOKEN * MAX_ARG_ROTATION) {
-                            thisRotArg = arg;
-                            thisRotLen = 1;
-                        }
+            if (bestRotLen >= 2) {
+                // Do a rotation if it can improve argument positioning
+                // by at least 2 arguments.  This is not always optimal,
+                // but it seems to catch common cases.
+                int dstEnd = state.indexOf(bestRotArg);
+                int srcEnd = goal.indexOf(bestRotArg);
+                int rotBy = dstEnd - srcEnd;
+                int dstBeg = dstEnd - (bestRotLen - 1);
+                int srcBeg = srcEnd - (bestRotLen - 1);
+                assert((dstEnd | dstBeg | srcEnd | srcBeg) >= 0); // no negs
+                // Make a span which covers both source and destination.
+                int rotBeg = Math.min(dstBeg, srcBeg);
+                int rotEnd = Math.max(dstEnd, srcEnd);
+                int score = 0;
+                for (int i = rotBeg; i <= rotEnd; i++) {
+                    if ((int)state.get(i) != (int)goal.get(i))
+                        score += 1;
+                }
+                List<Integer> rotSpan = state.subList(rotBeg, rotEnd+1);
+                Collections.rotate(rotSpan, -rotBy);  // reverse direction
+                for (int i = rotBeg; i <= rotEnd; i++) {
+                    if ((int)state.get(i) != (int)goal.get(i))
+                        score -= 1;
+                }
+                if (score >= 2) {
+                    // Improved at least two argument positions.  Do it.
+                    List<Class<?>> ptypes = Arrays.asList(oldType.parameterArray());
+                    Collections.rotate(ptypes.subList(rotBeg, rotEnd+1), -rotBy);
+                    MethodType rotType = MethodType.methodType(oldType.returnType(), ptypes);
+                    MethodHandle nextTarget
+                            = AdapterMethodHandle.makeRotateArguments(rotType, target,
+                                    rotBeg, rotSpan.size(), rotBy);
+                    if (nextTarget != null) {
+                        //System.out.println("Rot: "+rotSpan+" by "+rotBy);
+                        target = nextTarget;
+                        oldType = rotType;
+                        continue;
                     }
                 }
-                if (bestRotLen >= 2) {
-                    // Do a rotation if it can improve argument positioning
-                    // by at least 2 arguments.  This is not always optimal,
-                    // but it seems to catch common cases.
-                    int dstEnd = state.indexOf(bestRotArg);
-                    int srcEnd = goal.indexOf(bestRotArg);
-                    int rotBy = dstEnd - srcEnd;
-                    int dstBeg = dstEnd - (bestRotLen - 1);
-                    int srcBeg = srcEnd - (bestRotLen - 1);
-                    assert((dstEnd | dstBeg | srcEnd | srcBeg) >= 0); // no negs
-                    // Make a span which covers both source and destination.
-                    int rotBeg = Math.min(dstBeg, srcBeg);
-                    int rotEnd = Math.max(dstEnd, srcEnd);
-                    int score = 0;
-                    for (int i = rotBeg; i <= rotEnd; i++) {
-                        if ((int)state.get(i) != (int)goal.get(i))
-                            score += 1;
-                    }
-                    List<Integer> rotSpan = state.subList(rotBeg, rotEnd+1);
-                    Collections.rotate(rotSpan, -rotBy);  // reverse direction
-                    for (int i = rotBeg; i <= rotEnd; i++) {
-                        if ((int)state.get(i) != (int)goal.get(i))
-                            score -= 1;
-                    }
-                    if (score >= 2) {
-                        // Improved at least two argument positions.  Do it.
-                        List<Class<?>> ptypes = Arrays.asList(oldType.parameterArray());
-                        Collections.rotate(ptypes.subList(rotBeg, rotEnd+1), -rotBy);
-                        MethodType rotType = MethodType.methodType(oldType.returnType(), ptypes);
-                        MethodHandle nextTarget
-                                = AdapterMethodHandle.makeRotateArguments(rotType, target,
-                                        rotBeg, rotSpan.size(), rotBy);
-                        if (nextTarget != null) {
-                            //System.out.println("Rot: "+rotSpan+" by "+rotBy);
-                            target = nextTarget;
-                            oldType = rotType;
-                            continue;
-                        }
-                    }
-                    // Else de-rotate, and drop through to the swap-fest.
-                    Collections.rotate(rotSpan, rotBy);
-                }
+                // Else de-rotate, and drop through to the swap-fest.
+                Collections.rotate(rotSpan, rotBy);
+            }
 
-                // Now swap like the wind!
-                List<Class<?>> ptypes = Arrays.asList(oldType.parameterArray());
-                for (int i = 0; i < size; i++) {
-                    // What argument do I want here?
-                    int arg = goal.get(i);
-                    if (arg != state.get(i)) {
-                        // Where is it now?
-                        int j = state.indexOf(arg);
-                        Collections.swap(ptypes, i, j);
-                        MethodType swapType = MethodType.methodType(oldType.returnType(), ptypes);
-                        target = AdapterMethodHandle.makeSwapArguments(swapType, target, i, j);
-                        if (target == null)  throw newIllegalArgumentException("cannot swap");
-                        assert(target.type() == swapType);
-                        oldType = swapType;
-                        Collections.swap(state, i, j);
-                    }
+            // Now swap like the wind!
+            List<Class<?>> ptypes = Arrays.asList(oldType.parameterArray());
+            for (int i = 0; i < size; i++) {
+                // What argument do I want here?
+                int arg = goal.get(i);
+                if (arg != state.get(i)) {
+                    // Where is it now?
+                    int j = state.indexOf(arg);
+                    Collections.swap(ptypes, i, j);
+                    MethodType swapType = MethodType.methodType(oldType.returnType(), ptypes);
+                    target = AdapterMethodHandle.makeSwapArguments(swapType, target, i, j);
+                    if (target == null)  throw newIllegalArgumentException("cannot swap");
+                    assert(target.type() == swapType);
+                    oldType = swapType;
+                    Collections.swap(state, i, j);
                 }
-                // One pass of swapping must finish the job.
-                assert(state.equals(goal));
+            }
+            // One pass of swapping must finish the job.
+            assert(state.equals(goal));
+        }
+        while (!dups.isEmpty()) {
+            // Grab a contiguous trailing sequence of dups.
+            int grab = dups.size() - 1;
+            int dupArgPos = dups.get(grab), dupArgCount = 1;
+            while (grab - 1 >= 0) {
+                int dup0 = dups.get(grab - 1);
+                if (dup0 != dupArgPos - 1)  break;
+                dupArgPos -= 1;
+                dupArgCount += 1;
+                grab -= 1;
+            }
+            //if (dupArgCount > 1)  System.out.println("Dup: "+dups.subList(grab, dups.size()));
+            dups.subList(grab, dups.size()).clear();
+            // In the new target type drop that many args from the tail:
+            List<Class<?>> ptypes = oldType.parameterList();
+            ptypes = ptypes.subList(0, ptypes.size() - dupArgCount);
+            MethodType dupType = MethodType.methodType(oldType.returnType(), ptypes);
+            target = AdapterMethodHandle.makeDupArguments(dupType, target, dupArgPos, dupArgCount);
+            if (target == null)
+                throw newIllegalArgumentException("cannot dup");
+            oldType = target.type();
+        }
+        while (!drops.isEmpty()) {
+            // Grab a contiguous initial sequence of drops.
+            int dropArgPos = drops.get(0), dropArgCount = 1;
+            while (dropArgCount < drops.size()) {
+                int drop1 = drops.get(dropArgCount);
+                if (drop1 != dropArgPos + dropArgCount)  break;
+                dropArgCount += 1;
             }
-            while (!dups.isEmpty()) {
-                // Grab a contiguous trailing sequence of dups.
-                int grab = dups.size() - 1;
-                int dupArgPos = dups.get(grab), dupArgCount = 1;
-                while (grab - 1 >= 0) {
-                    int dup0 = dups.get(grab - 1);
-                    if (dup0 != dupArgPos - 1)  break;
-                    dupArgPos -= 1;
-                    dupArgCount += 1;
-                    grab -= 1;
-                }
-                //if (dupArgCount > 1)  System.out.println("Dup: "+dups.subList(grab, dups.size()));
-                dups.subList(grab, dups.size()).clear();
-                // In the new target type drop that many args from the tail:
-                List<Class<?>> ptypes = oldType.parameterList();
-                ptypes = ptypes.subList(0, ptypes.size() - dupArgCount);
-                MethodType dupType = MethodType.methodType(oldType.returnType(), ptypes);
-                target = AdapterMethodHandle.makeDupArguments(dupType, target, dupArgPos, dupArgCount);
-                if (target == null)
-                    throw newIllegalArgumentException("cannot dup");
-                oldType = target.type();
+            //if (dropArgCount > 1)  System.out.println("Drop: "+drops.subList(0, dropArgCount));
+            drops.subList(0, dropArgCount).clear();
+            List<Class<?>> dropTypes = newType.parameterList()
+                    .subList(dropArgPos, dropArgPos + dropArgCount);
+            MethodType dropType = oldType.insertParameterTypes(dropArgPos, dropTypes);
+            target = AdapterMethodHandle.makeDropArguments(dropType, target, dropArgPos, dropArgCount);
+            if (target == null)  throw newIllegalArgumentException("cannot drop");
+            oldType = target.type();
+        }
+        return convertArguments(target, newType, oldType, 0);
+    }
+
+    /*non-public*/ static
+    MethodHandle convertArguments(MethodHandle target, MethodType newType, int level) {
+        MethodType oldType = target.type();
+        if (oldType.equals(newType))
+            return target;
+        assert(level > 1 || oldType.isConvertibleTo(newType));
+        MethodHandle retFilter = null;
+        Class<?> oldRT = oldType.returnType();
+        Class<?> newRT = newType.returnType();
+        if (!VerifyType.isNullConversion(oldRT, newRT)) {
+            if (oldRT == void.class) {
+                Wrapper wrap = newRT.isPrimitive() ? Wrapper.forPrimitiveType(newRT) : Wrapper.OBJECT;
+                retFilter = ValueConversions.zeroConstantFunction(wrap);
+            } else {
+                retFilter = MethodHandles.identity(newRT);
+                retFilter = convertArguments(retFilter, retFilter.type().changeParameterType(0, oldRT), level);
             }
-            while (!drops.isEmpty()) {
-                // Grab a contiguous initial sequence of drops.
-                int dropArgPos = drops.get(0), dropArgCount = 1;
-                while (dropArgCount < drops.size()) {
-                    int drop1 = drops.get(dropArgCount);
-                    if (drop1 != dropArgPos + dropArgCount)  break;
-                    dropArgCount += 1;
-                }
-                //if (dropArgCount > 1)  System.out.println("Drop: "+drops.subList(0, dropArgCount));
-                drops.subList(0, dropArgCount).clear();
-                List<Class<?>> dropTypes = newType.parameterList()
-                        .subList(dropArgPos, dropArgPos + dropArgCount);
-                MethodType dropType = oldType.insertParameterTypes(dropArgPos, dropTypes);
-                target = AdapterMethodHandle.makeDropArguments(dropType, target, dropArgPos, dropArgCount);
-                if (target == null)  throw newIllegalArgumentException("cannot drop");
-                oldType = target.type();
-            }
+            newType = newType.changeReturnType(oldRT);
+        }
+        MethodHandle res = null;
+        Exception ex = null;
+        try {
+            res = convertArguments(target, newType, oldType, level);
+        } catch (IllegalArgumentException ex1) {
+            ex = ex1;
         }
+        if (res == null) {
+            WrongMethodTypeException wmt = new WrongMethodTypeException("cannot convert to "+newType+": "+target);
+            wmt.initCause(ex);
+            throw wmt;
+        }
+        if (retFilter != null)
+            res = MethodHandles.filterReturnValue(res, retFilter);
+        return res;
+    }
+
+    static MethodHandle convertArguments(MethodHandle target,
+                                                MethodType newType,
+                                                MethodType oldType,
+                                                int level) {
+        assert(oldType.parameterCount() == target.type().parameterCount());
         if (newType == oldType)
             return target;
         if (oldType.parameterCount() != newType.parameterCount())
-            throw newIllegalArgumentException("mismatched parameter count");
-        MethodHandle res = AdapterMethodHandle.makePairwiseConvert(newType, target);
+            throw newIllegalArgumentException("mismatched parameter count", oldType, newType);
+        MethodHandle res = AdapterMethodHandle.makePairwiseConvert(newType, target, level);
         if (res != null)
             return res;
+        // We can come here in the case of target(int)void => (Object)void,
+        // because the unboxing logic for Object => int is complex.
         int argc = oldType.parameterCount();
+        assert(MethodHandleNatives.workaroundWithoutRicochetFrames());  // this code is deprecated
         // The JVM can't do it directly, so fill in the gap with a Java adapter.
         // TO DO: figure out what to put here from case-by-case experience
         // Use a heavier method:  Convert all the arguments to Object,
         // then back to the desired types.  We might have to use Java-based
         // method handles to do this.
         MethodType objType = MethodType.genericMethodType(argc);
-        MethodHandle objTarget = AdapterMethodHandle.makePairwiseConvert(objType, target);
+        MethodHandle objTarget = AdapterMethodHandle.makePairwiseConvert(objType, target, level);
         if (objTarget == null)
             objTarget = FromGeneric.make(target);
-        res = AdapterMethodHandle.makePairwiseConvert(newType, objTarget);
+        res = AdapterMethodHandle.makePairwiseConvert(newType, objTarget, level);
         if (res != null)
             return res;
         return ToGeneric.make(newType, objTarget);
     }
 
+    static MethodHandle spreadArguments(MethodHandle target, Class<?> arrayType, int arrayLength) {
+        MethodType oldType = target.type();
+        int nargs = oldType.parameterCount();
+        int keepPosArgs = nargs - arrayLength;
+        MethodType newType = oldType
+                .dropParameterTypes(keepPosArgs, nargs)
+                .insertParameterTypes(keepPosArgs, arrayType);
+        return spreadArguments(target, newType, keepPosArgs, arrayType, arrayLength);
+    }
+    static MethodHandle spreadArguments(MethodHandle target, MethodType newType, int spreadArgPos) {
+        int arrayLength = target.type().parameterCount() - spreadArgPos;
+        return spreadArguments(target, newType, spreadArgPos, Object[].class, arrayLength);
+    }
     static MethodHandle spreadArguments(MethodHandle target,
                                                MethodType newType,
-                                               int spreadArg) {
+                                               int spreadArgPos,
+                                               Class<?> arrayType,
+                                               int arrayLength) {
         // TO DO: maybe allow the restarg to be Object and implicitly cast to Object[]
         MethodType oldType = target.type();
         // spread the last argument of newType to oldType
-        int spreadCount = oldType.parameterCount() - spreadArg;
-        Class<Object[]> spreadArgType = Object[].class;
-        MethodHandle res = AdapterMethodHandle.makeSpreadArguments(newType, target, spreadArgType, spreadArg, spreadCount);
-        if (res != null)
-            return res;
-        // try an intermediate adapter
-        Class<?> spreadType = null;
-        if (spreadArg < 0 || spreadArg >= newType.parameterCount()
-            || !VerifyType.isSpreadArgType(spreadType = newType.parameterType(spreadArg)))
-            throw newIllegalArgumentException("no restarg in "+newType);
-        Class<?>[] ptypes = oldType.parameterArray();
-        for (int i = 0; i < spreadCount; i++)
-            ptypes[spreadArg + i] = VerifyType.spreadArgElementType(spreadType, i);
-        MethodType midType = MethodType.methodType(newType.returnType(), ptypes);
-        // after spreading, some arguments may need further conversion
-        MethodHandle target2 = convertArguments(target, midType, oldType, null);
-        if (target2 == null)
-            throw new UnsupportedOperationException("NYI: convert "+midType+" =calls=> "+oldType);
-        res = AdapterMethodHandle.makeSpreadArguments(newType, target2, spreadArgType, spreadArg, spreadCount);
-        if (res != null)
-            return res;
-        res = SpreadGeneric.make(target2, spreadCount);
-        if (res != null)
-            res = convertArguments(res, newType, res.type(), null);
+        assert(arrayLength == oldType.parameterCount() - spreadArgPos);
+        assert(newType.parameterType(spreadArgPos) == arrayType);
+        MethodHandle res = AdapterMethodHandle.makeSpreadArguments(newType, target, arrayType, spreadArgPos, arrayLength);
+        if (res == null)  throw new IllegalArgumentException("spread on "+target+" with "+arrayType.getSimpleName());
         return res;
     }
 
     static MethodHandle collectArguments(MethodHandle target,
+                                                int collectArg,
+                                                MethodHandle collector) {
+        MethodType type = target.type();
+        Class<?> collectType = collector.type().returnType();
+        if (collectType != type.parameterType(collectArg))
+            target = target.asType(type.changeParameterType(collectArg, collectType));
+        MethodType newType = type
+                .dropParameterTypes(collectArg, collectArg+1)
+                .insertParameterTypes(collectArg, collector.type().parameterArray());
+        return collectArguments(target, newType, collectArg, collector);
+    }
+    static MethodHandle collectArguments(MethodHandle target,
                                                 MethodType newType,
                                                 int collectArg,
                                                 MethodHandle collector) {
         MethodType oldType = target.type();     // (a...,c)=>r
-        if (collector == null) {
-            int numCollect = newType.parameterCount() - oldType.parameterCount() + 1;
-            collector = ValueConversions.varargsArray(numCollect);
-        }
         //         newType                      // (a..., b...)=>r
         MethodType colType = collector.type();  // (b...)=>c
         //         oldType                      // (a..., b...)=>r
         assert(newType.parameterCount() == collectArg + colType.parameterCount());
         assert(oldType.parameterCount() == collectArg + 1);
-        MethodHandle gtarget = convertArguments(target, oldType.generic(), oldType, null);
-        MethodHandle gcollector = convertArguments(collector, colType.generic(), colType, null);
-        if (gtarget == null || gcollector == null)  return null;
-        MethodHandle gresult = FilterGeneric.makeArgumentCollector(gcollector, gtarget);
-        MethodHandle result = convertArguments(gresult, newType, gresult.type(), null);
+        MethodHandle result = null;
+        if (AdapterMethodHandle.canCollectArguments(oldType, colType, collectArg, false)) {
+            result = AdapterMethodHandle.makeCollectArguments(target, collector, collectArg, false);
+        }
+        if (result == null) {
+            assert(MethodHandleNatives.workaroundWithoutRicochetFrames());  // this code is deprecated
+            MethodHandle gtarget = convertArguments(target, oldType.generic(), oldType, 0);
+            MethodHandle gcollector = convertArguments(collector, colType.generic(), colType, 0);
+            if (gtarget == null || gcollector == null)  return null;
+            MethodHandle gresult = FilterGeneric.makeArgumentCollector(gcollector, gtarget);
+            result = convertArguments(gresult, newType, gresult.type(), 0);
+        }
         return result;
     }
 
     static MethodHandle filterArgument(MethodHandle target,
-                                              int pos,
-                                              MethodHandle filter) {
-        MethodType ttype = target.type(), gttype = ttype.generic();
+                                       int pos,
+                                       MethodHandle filter) {
+        MethodType ttype = target.type();
+        MethodType ftype = filter.type();
+        assert(ftype.parameterCount() == 1);
+        MethodType rtype = ttype.changeParameterType(pos, ftype.parameterType(0));
+        MethodType gttype = ttype.generic();
         if (ttype != gttype) {
-            target = convertArguments(target, gttype, ttype, null);
+            target = convertArguments(target, gttype, ttype, 0);
             ttype = gttype;
         }
-        MethodType ftype = filter.type(), gftype = ftype.generic();
-        if (ftype.parameterCount() != 1)
-            throw new InternalError();
+        MethodType gftype = ftype.generic();
         if (ftype != gftype) {
-            filter = convertArguments(filter, gftype, ftype, null);
+            filter = convertArguments(filter, gftype, ftype, 0);
             ftype = gftype;
         }
-        if (ftype == ttype) {
+        MethodHandle result = null;
+        if (AdapterMethodHandle.canCollectArguments(ttype, ftype, pos, false)) {
+            result = AdapterMethodHandle.makeCollectArguments(target, filter, pos, false);
+        }
+        if (result == null) {
+            assert(MethodHandleNatives.workaroundWithoutRicochetFrames());  // this code is deprecated
+            if (ftype == ttype) {
             // simple unary case
-            return FilterOneArgument.make(filter, target);
+                result = FilterOneArgument.make(filter, target);
+            } else {
+                result = FilterGeneric.makeArgumentFilter(pos, filter, target);
+            }
         }
-        return FilterGeneric.makeArgumentFilter(pos, filter, target);
+        if (result.type() != rtype)
+            result = result.asType(rtype);
+        return result;
     }
 
     static MethodHandle foldArguments(MethodHandle target,
-                                             MethodType newType,
-                                             MethodHandle combiner) {
+                                      MethodType newType,
+                                      int foldPos,
+                                      MethodHandle combiner) {
         MethodType oldType = target.type();
         MethodType ctype = combiner.type();
-        MethodHandle gtarget = convertArguments(target, oldType.generic(), oldType, null);
-        MethodHandle gcombiner = convertArguments(combiner, ctype.generic(), ctype, null);
+        if (AdapterMethodHandle.canCollectArguments(oldType, ctype, foldPos, true)) {
+            MethodHandle res = AdapterMethodHandle.makeCollectArguments(target, combiner, foldPos, true);
+            if (res != null)  return res;
+        }
+        assert(MethodHandleNatives.workaroundWithoutRicochetFrames());  // this code is deprecated
+        if (foldPos != 0)  return null;
+        MethodHandle gtarget = convertArguments(target, oldType.generic(), oldType, 0);
+        MethodHandle gcombiner = convertArguments(combiner, ctype.generic(), ctype, 0);
+        if (ctype.returnType() == void.class) {
+            gtarget = dropArguments(gtarget, oldType.generic().insertParameterTypes(foldPos, Object.class), foldPos);
+        }
         if (gtarget == null || gcombiner == null)  return null;
         MethodHandle gresult = FilterGeneric.makeArgumentFolder(gcombiner, gtarget);
-        MethodHandle result = convertArguments(gresult, newType, gresult.type(), null);
-        return result;
+        return convertArguments(gresult, newType, gresult.type(), 0);
     }
 
     static
@@ -802,6 +879,7 @@
             this.target = target;
             this.fallback = fallback;
         }
+        // FIXME: Build the control flow out of foldArguments.
         static MethodHandle make(MethodHandle test, MethodHandle target, MethodHandle fallback) {
             MethodType type = target.type();
             int nargs = type.parameterCount();
@@ -809,12 +887,12 @@
                 MethodHandle invoke = INVOKES[nargs];
                 MethodType gtype = type.generic();
                 assert(invoke.type().dropParameterTypes(0,1) == gtype);
-                MethodHandle gtest = convertArguments(test, gtype.changeReturnType(boolean.class), test.type(), null);
-                MethodHandle gtarget = convertArguments(target, gtype, type, null);
-                MethodHandle gfallback = convertArguments(fallback, gtype, type, null);
+                MethodHandle gtest = convertArguments(test, gtype.changeReturnType(boolean.class), test.type(), 0);
+                MethodHandle gtarget = convertArguments(target, gtype, type, 0);
+                MethodHandle gfallback = convertArguments(fallback, gtype, type, 0);
                 if (gtest == null || gtarget == null || gfallback == null)  return null;
                 MethodHandle gguard = new GuardWithTest(invoke, gtest, gtarget, gfallback);
-                return convertArguments(gguard, type, gtype, null);
+                return convertArguments(gguard, type, gtype, 0);
             } else {
                 MethodHandle invoke = VARARGS_INVOKE;
                 MethodType gtype = MethodType.genericMethodType(1);
@@ -925,8 +1003,9 @@
         GuardWithCatch(MethodHandle target, Class<? extends Throwable> exType, MethodHandle catcher) {
             this(INVOKES[target.type().parameterCount()], target, exType, catcher);
         }
-       GuardWithCatch(MethodHandle invoker,
-                      MethodHandle target, Class<? extends Throwable> exType, MethodHandle catcher) {
+        // FIXME: Build the control flow out of foldArguments.
+        GuardWithCatch(MethodHandle invoker,
+                       MethodHandle target, Class<? extends Throwable> exType, MethodHandle catcher) {
             super(invoker);
             this.target = target;
             this.exType = exType;
@@ -1057,11 +1136,11 @@
         if (nargs < GuardWithCatch.INVOKES.length) {
             MethodType gtype = type.generic();
             MethodType gcatchType = gtype.insertParameterTypes(0, Throwable.class);
-            MethodHandle gtarget = convertArguments(target, gtype, type, null);
-            MethodHandle gcatcher = convertArguments(catcher, gcatchType, ctype, null);
+            MethodHandle gtarget = convertArguments(target, gtype, type, 0);
+            MethodHandle gcatcher = convertArguments(catcher, gcatchType, ctype, 0);
             MethodHandle gguard = new GuardWithCatch(gtarget, exType, gcatcher);
             if (gtarget == null || gcatcher == null || gguard == null)  return null;
-            return convertArguments(gguard, type, gtype, null);
+            return convertArguments(gguard, type, gtype, 0);
         } else {
             MethodType gtype = MethodType.genericMethodType(0, true);
             MethodType gcatchType = gtype.insertParameterTypes(0, Throwable.class);