changeset 9998:24ac0f2fad86

8057922: Improve LambdaForm sharing by using LambdaFormEditor more extensively Reviewed-by: vlivanov, psandoz Contributed-by: john.r.rose@oracle.com
author vlivanov
date Wed, 10 Sep 2014 18:34:42 +0400
parents 914aea3f4893
children 0a85994e76cb
files src/share/classes/java/lang/invoke/LambdaForm.java src/share/classes/java/lang/invoke/LambdaFormBuffer.java src/share/classes/java/lang/invoke/LambdaFormEditor.java src/share/classes/java/lang/invoke/MethodHandle.java src/share/classes/java/lang/invoke/MethodHandleImpl.java src/share/classes/java/lang/invoke/MethodHandleStatics.java src/share/classes/java/lang/invoke/MethodHandles.java
diffstat 7 files changed, 675 insertions(+), 65 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/java/lang/invoke/LambdaForm.java	Wed Sep 10 18:34:40 2014 +0400
+++ b/src/share/classes/java/lang/invoke/LambdaForm.java	Wed Sep 10 18:34:42 2014 +0400
@@ -802,28 +802,6 @@
         return rval;
     }
 
-    //** This transform is applied (statically) to every name.function. */
-    /*
-    private static MethodHandle eraseSubwordTypes(MethodHandle mh) {
-        MethodType mt = mh.type();
-        if (mt.hasPrimitives()) {
-            mt = mt.changeReturnType(eraseSubwordType(mt.returnType()));
-            for (int i = 0; i < mt.parameterCount(); i++) {
-                mt = mt.changeParameterType(i, eraseSubwordType(mt.parameterType(i)));
-            }
-            mh = MethodHandles.explicitCastArguments(mh, mt);
-        }
-        return mh;
-    }
-    private static Class<?> eraseSubwordType(Class<?> type) {
-        if (!type.isPrimitive())  return type;
-        if (type == int.class)  return type;
-        Wrapper w = Wrapper.forPrimitiveType(type);
-        if (w.isSubwordOrInt())  return int.class;
-        return type;
-    }
-    */
-
     static void traceInterpreter(String event, Object obj, Object... args) {
         if (TRACE_INTERPRETER) {
             System.out.println("LFI: "+event+" "+(obj != null ? obj : "")+(args != null && args.length != 0 ? Arrays.asList(args) : ""));
--- a/src/share/classes/java/lang/invoke/LambdaFormBuffer.java	Wed Sep 10 18:34:40 2014 +0400
+++ b/src/share/classes/java/lang/invoke/LambdaFormBuffer.java	Wed Sep 10 18:34:42 2014 +0400
@@ -59,7 +59,7 @@
             resultName = names[result];
     }
 
-    LambdaForm lambdaForm() {
+    private LambdaForm lambdaForm() {
         assert(!inTrans());  // need endEdit call to tidy things up
         return new LambdaForm(debugName, arity, nameArray(), resultIndex());
     }
@@ -276,7 +276,7 @@
     }
 
     /** Finish a transaction. */
-    void endEdit() {
+    LambdaForm endEdit() {
         assert(verifyFirstChange());
         // Assuming names have been changed pairwise from originalNames[i] to names[i],
         // update arguments to ensure referential integrity.
@@ -316,6 +316,7 @@
             arity -= exprp;
         }
         assert(verifyArity());
+        return lambdaForm();
     }
 
     private Name[] copyNamesInto(Name[] buffer) {
--- a/src/share/classes/java/lang/invoke/LambdaFormEditor.java	Wed Sep 10 18:34:40 2014 +0400
+++ b/src/share/classes/java/lang/invoke/LambdaFormEditor.java	Wed Sep 10 18:34:42 2014 +0400
@@ -443,8 +443,383 @@
             buf.insertParameter(0, newBaseAddress);
         }
 
-        buf.endEdit();
-        form = buf.lambdaForm();
+        form = buf.endEdit();
+        return putInCache(key, form);
+    }
+
+    LambdaForm addArgumentForm(int pos, BasicType type) {
+        Transform key = Transform.of(Transform.Kind.ADD_ARG, pos, type.ordinal());
+        LambdaForm form = getInCache(key);
+        if (form != null) {
+            assert(form.arity == lambdaForm.arity+1);
+            assert(form.parameterType(pos) == type);
+            return form;
+        }
+        LambdaFormBuffer buf = buffer();
+        buf.startEdit();
+
+        buf.insertParameter(pos, new Name(type));
+
+        form = buf.endEdit();
+        return putInCache(key, form);
+    }
+
+    LambdaForm dupArgumentForm(int srcPos, int dstPos) {
+        Transform key = Transform.of(Transform.Kind.DUP_ARG, srcPos, dstPos);
+        LambdaForm form = getInCache(key);
+        if (form != null) {
+            assert(form.arity == lambdaForm.arity-1);
+            return form;
+        }
+        LambdaFormBuffer buf = buffer();
+        buf.startEdit();
+
+        assert(lambdaForm.parameter(srcPos).constraint == null);
+        assert(lambdaForm.parameter(dstPos).constraint == null);
+        buf.replaceParameterByCopy(dstPos, srcPos);
+
+        form = buf.endEdit();
+        return putInCache(key, form);
+    }
+
+    LambdaForm spreadArgumentsForm(int pos, Class<?> arrayType, int arrayLength) {
+        Class<?> elementType = arrayType.getComponentType();
+        Class<?> erasedArrayType = arrayType;
+        if (!elementType.isPrimitive())
+            erasedArrayType = Object[].class;
+        BasicType bt = basicType(elementType);
+        int elementTypeKey = bt.ordinal();
+        if (bt.basicTypeClass() != elementType) {
+            if (elementType.isPrimitive()) {
+                elementTypeKey = TYPE_LIMIT + Wrapper.forPrimitiveType(elementType).ordinal();
+            }
+        }
+        Transform key = Transform.of(Transform.Kind.SPREAD_ARGS, pos, elementTypeKey, arrayLength);
+        LambdaForm form = getInCache(key);
+        if (form != null) {
+            assert(form.arity == lambdaForm.arity - arrayLength + 1);
+            return form;
+        }
+        LambdaFormBuffer buf = buffer();
+        buf.startEdit();
+
+        assert(pos <= MethodType.MAX_JVM_ARITY);
+        assert(pos + arrayLength <= lambdaForm.arity);
+        assert(pos > 0);  // cannot spread the MH arg itself
+
+        Name spreadParam = new Name(L_TYPE);
+        Name checkSpread = new Name(MethodHandleImpl.Lazy.NF_checkSpreadArgument, spreadParam, arrayLength);
+
+        // insert the new expressions
+        int exprPos = lambdaForm.arity();
+        buf.insertExpression(exprPos++, checkSpread);
+        // adjust the arguments
+        MethodHandle aload = MethodHandles.arrayElementGetter(erasedArrayType);
+        for (int i = 0; i < arrayLength; i++) {
+            Name loadArgument = new Name(aload, spreadParam, i);
+            buf.insertExpression(exprPos + i, loadArgument);
+            buf.replaceParameterByCopy(pos + i, exprPos + i);
+        }
+        buf.insertParameter(pos, spreadParam);
+
+        form = buf.endEdit();
+        return putInCache(key, form);
+    }
+
+    LambdaForm collectArgumentsForm(int pos, MethodType collectorType) {
+        int collectorArity = collectorType.parameterCount();
+        boolean dropResult = (collectorType.returnType() == void.class);
+        if (collectorArity == 1 && !dropResult) {
+            return filterArgumentForm(pos, basicType(collectorType.parameterType(0)));
+        }
+        BasicType[] newTypes = BasicType.basicTypes(collectorType.parameterList());
+        Transform.Kind kind = (dropResult
+                ? Transform.Kind.COLLECT_ARGS_TO_VOID
+                : Transform.Kind.COLLECT_ARGS);
+        if (dropResult && collectorArity == 0)  pos = 1;  // pure side effect
+        Transform key = Transform.of(kind, pos, collectorArity, BasicType.basicTypesOrd(newTypes));
+        LambdaForm form = getInCache(key);
+        if (form != null) {
+            assert(form.arity == lambdaForm.arity - (dropResult ? 0 : 1) + collectorArity);
+            return form;
+        }
+        form = makeArgumentCombinationForm(pos, collectorType, false, dropResult);
+        return putInCache(key, form);
+    }
+
+    LambdaForm collectArgumentArrayForm(int pos, MethodHandle arrayCollector) {
+        MethodType collectorType = arrayCollector.type();
+        int collectorArity = collectorType.parameterCount();
+        assert(arrayCollector.intrinsicName() == Intrinsic.NEW_ARRAY);
+        Class<?> arrayType = collectorType.returnType();
+        Class<?> elementType = arrayType.getComponentType();
+        BasicType argType = basicType(elementType);
+        int argTypeKey = argType.ordinal();
+        if (argType.basicTypeClass() != elementType) {
+            // return null if it requires more metadata (like String[].class)
+            if (!elementType.isPrimitive())
+                return null;
+            argTypeKey = TYPE_LIMIT + Wrapper.forPrimitiveType(elementType).ordinal();
+        }
+        assert(collectorType.parameterList().equals(Collections.nCopies(collectorArity, elementType)));
+        Transform.Kind kind = Transform.Kind.COLLECT_ARGS_TO_ARRAY;
+        Transform key = Transform.of(kind, pos, collectorArity, argTypeKey);
+        LambdaForm form = getInCache(key);
+        if (form != null) {
+            assert(form.arity == lambdaForm.arity - 1 + collectorArity);
+            return form;
+        }
+        LambdaFormBuffer buf = buffer();
+        buf.startEdit();
+
+        assert(pos + 1 <= lambdaForm.arity);
+        assert(pos > 0);  // cannot filter the MH arg itself
+
+        Name[] newParams = new Name[collectorArity];
+        for (int i = 0; i < collectorArity; i++) {
+            newParams[i] = new Name(pos + i, argType);
+        }
+        Name callCombiner = new Name(arrayCollector, (Object[]) /*...*/ newParams);
+
+        // insert the new expression
+        int exprPos = lambdaForm.arity();
+        buf.insertExpression(exprPos, callCombiner);
+
+        // insert new arguments
+        int argPos = pos + 1;  // skip result parameter
+        for (Name newParam : newParams) {
+            buf.insertParameter(argPos++, newParam);
+        }
+        assert(buf.lastIndexOf(callCombiner) == exprPos+newParams.length);
+        buf.replaceParameterByCopy(pos, exprPos+newParams.length);
+
+        form = buf.endEdit();
+        return putInCache(key, form);
+    }
+
+    LambdaForm filterArgumentForm(int pos, BasicType newType) {
+        Transform key = Transform.of(Transform.Kind.FILTER_ARG, pos, newType.ordinal());
+        LambdaForm form = getInCache(key);
+        if (form != null) {
+            assert(form.arity == lambdaForm.arity);
+            assert(form.parameterType(pos) == newType);
+            return form;
+        }
+
+        BasicType oldType = lambdaForm.parameterType(pos);
+        MethodType filterType = MethodType.methodType(oldType.basicTypeClass(),
+                newType.basicTypeClass());
+        form = makeArgumentCombinationForm(pos, filterType, false, false);
         return putInCache(key, form);
     }
+
+    private LambdaForm makeArgumentCombinationForm(int pos,
+                                                   MethodType combinerType,
+                                                   boolean keepArguments, boolean dropResult) {
+        LambdaFormBuffer buf = buffer();
+        buf.startEdit();
+        int combinerArity = combinerType.parameterCount();
+        int resultArity = (dropResult ? 0 : 1);
+
+        assert(pos <= MethodType.MAX_JVM_ARITY);
+        assert(pos + resultArity + (keepArguments ? combinerArity : 0) <= lambdaForm.arity);
+        assert(pos > 0);  // cannot filter the MH arg itself
+        assert(combinerType == combinerType.basicType());
+        assert(combinerType.returnType() != void.class || dropResult);
+
+        BoundMethodHandle.SpeciesData oldData = oldSpeciesData();
+        BoundMethodHandle.SpeciesData newData = newSpeciesData(L_TYPE);
+
+        // The newly created LF will run with a different BMH.
+        // Switch over any pre-existing BMH field references to the new BMH class.
+        Name oldBaseAddress = lambdaForm.parameter(0);  // BMH holding the values
+        buf.replaceFunctions(oldData.getterFunctions(), newData.getterFunctions(), oldBaseAddress);
+        Name newBaseAddress = oldBaseAddress.withConstraint(newData);
+        buf.renameParameter(0, newBaseAddress);
+
+        Name getCombiner = new Name(newData.getterFunction(oldData.fieldCount()), newBaseAddress);
+        Object[] combinerArgs = new Object[1 + combinerArity];
+        combinerArgs[0] = getCombiner;
+        Name[] newParams;
+        if (keepArguments) {
+            newParams = new Name[0];
+            System.arraycopy(lambdaForm.names, pos + resultArity,
+                             combinerArgs, 1, combinerArity);
+        } else {
+            newParams = new Name[combinerArity];
+            BasicType[] newTypes = basicTypes(combinerType.parameterList());
+            for (int i = 0; i < newTypes.length; i++) {
+                newParams[i] = new Name(pos + i, newTypes[i]);
+            }
+            System.arraycopy(newParams, 0,
+                             combinerArgs, 1, combinerArity);
+        }
+        Name callCombiner = new Name(combinerType, combinerArgs);
+
+        // insert the two new expressions
+        int exprPos = lambdaForm.arity();
+        buf.insertExpression(exprPos+0, getCombiner);
+        buf.insertExpression(exprPos+1, callCombiner);
+
+        // insert new arguments, if needed
+        int argPos = pos + resultArity;  // skip result parameter
+        for (Name newParam : newParams) {
+            buf.insertParameter(argPos++, newParam);
+        }
+        assert(buf.lastIndexOf(callCombiner) == exprPos+1+newParams.length);
+        if (!dropResult) {
+            buf.replaceParameterByCopy(pos, exprPos+1+newParams.length);
+        }
+
+        return buf.endEdit();
+    }
+
+    LambdaForm filterReturnForm(BasicType newType, boolean constantZero) {
+        Transform.Kind kind = (constantZero ? Transform.Kind.FILTER_RETURN_TO_ZERO : Transform.Kind.FILTER_RETURN);
+        Transform key = Transform.of(kind, newType.ordinal());
+        LambdaForm form = getInCache(key);
+        if (form != null) {
+            assert(form.arity == lambdaForm.arity);
+            assert(form.returnType() == newType);
+            return form;
+        }
+        LambdaFormBuffer buf = buffer();
+        buf.startEdit();
+
+        int insPos = lambdaForm.names.length;
+        Name callFilter;
+        if (constantZero) {
+            // Synthesize a constant zero value for the given type.
+            if (newType == V_TYPE)
+                callFilter = null;
+            else
+                callFilter = new Name(constantZero(newType));
+        } else {
+            BoundMethodHandle.SpeciesData oldData = oldSpeciesData();
+            BoundMethodHandle.SpeciesData newData = newSpeciesData(L_TYPE);
+
+            // The newly created LF will run with a different BMH.
+            // Switch over any pre-existing BMH field references to the new BMH class.
+            Name oldBaseAddress = lambdaForm.parameter(0);  // BMH holding the values
+            buf.replaceFunctions(oldData.getterFunctions(), newData.getterFunctions(), oldBaseAddress);
+            Name newBaseAddress = oldBaseAddress.withConstraint(newData);
+            buf.renameParameter(0, newBaseAddress);
+
+            Name getFilter = new Name(newData.getterFunction(oldData.fieldCount()), newBaseAddress);
+            buf.insertExpression(insPos++, getFilter);
+            BasicType oldType = lambdaForm.returnType();
+            if (oldType == V_TYPE) {
+                MethodType filterType = MethodType.methodType(newType.basicTypeClass());
+                callFilter = new Name(filterType, getFilter);
+            } else {
+                MethodType filterType = MethodType.methodType(newType.basicTypeClass(), oldType.basicTypeClass());
+                callFilter = new Name(filterType, getFilter, lambdaForm.names[lambdaForm.result]);
+            }
+        }
+
+        if (callFilter != null)
+            buf.insertExpression(insPos++, callFilter);
+        buf.setResult(callFilter);
+
+        form = buf.endEdit();
+        return putInCache(key, form);
+    }
+
+    LambdaForm foldArgumentsForm(int foldPos, boolean dropResult, MethodType combinerType) {
+        int combinerArity = combinerType.parameterCount();
+        Transform.Kind kind = (dropResult ? Transform.Kind.FOLD_ARGS_TO_VOID : Transform.Kind.FOLD_ARGS);
+        Transform key = Transform.of(kind, foldPos, combinerArity);
+        LambdaForm form = getInCache(key);
+        if (form != null) {
+            assert(form.arity == lambdaForm.arity - (kind == Transform.Kind.FOLD_ARGS ? 1 : 0));
+            return form;
+        }
+        form = makeArgumentCombinationForm(foldPos, combinerType, true, dropResult);
+        return putInCache(key, form);
+    }
+
+    LambdaForm permuteArgumentsForm(int skip, int[] reorder) {
+        assert(skip == 1);  // skip only the leading MH argument, names[0]
+        int length = lambdaForm.names.length;
+        int outArgs = reorder.length;
+        int inTypes = 0;
+        boolean nullPerm = true;
+        for (int i = 0; i < reorder.length; i++) {
+            int inArg = reorder[i];
+            if (inArg != i)  nullPerm = false;
+            inTypes = Math.max(inTypes, inArg+1);
+        }
+        assert(skip + reorder.length == lambdaForm.arity);
+        if (nullPerm)  return lambdaForm;  // do not bother to cache
+        Transform key = Transform.of(Transform.Kind.PERMUTE_ARGS, reorder);
+        LambdaForm form = getInCache(key);
+        if (form != null) {
+            assert(form.arity == skip+inTypes) : form;
+            return form;
+        }
+
+        BasicType[] types = new BasicType[inTypes];
+        for (int i = 0; i < outArgs; i++) {
+            int inArg = reorder[i];
+            types[inArg] = lambdaForm.names[skip + i].type;
+        }
+        assert (skip + outArgs == lambdaForm.arity);
+        assert (permutedTypesMatch(reorder, types, lambdaForm.names, skip));
+        int pos = 0;
+        while (pos < outArgs && reorder[pos] == pos) {
+            pos += 1;
+        }
+        Name[] names2 = new Name[length - outArgs + inTypes];
+        System.arraycopy(lambdaForm.names, 0, names2, 0, skip + pos);
+        int bodyLength = length - lambdaForm.arity;
+        System.arraycopy(lambdaForm.names, skip + outArgs, names2, skip + inTypes, bodyLength);
+        int arity2 = names2.length - bodyLength;
+        int result2 = lambdaForm.result;
+        if (result2 >= 0) {
+            if (result2 < skip + outArgs) {
+                result2 = reorder[result2 - skip];
+            } else {
+                result2 = result2 - outArgs + inTypes;
+            }
+        }
+        for (int j = pos; j < outArgs; j++) {
+            Name n = lambdaForm.names[skip + j];
+            int i = reorder[j];
+            Name n2 = names2[skip + i];
+            if (n2 == null) {
+                names2[skip + i] = n2 = new Name(types[i]);
+            } else {
+                assert (n2.type == types[i]);
+            }
+            for (int k = arity2; k < names2.length; k++) {
+                names2[k] = names2[k].replaceName(n, n2);
+            }
+        }
+        for (int i = skip + pos; i < arity2; i++) {
+            if (names2[i] == null) {
+                names2[i] = argument(i, types[i - skip]);
+            }
+        }
+        for (int j = lambdaForm.arity; j < lambdaForm.names.length; j++) {
+            int i = j - lambdaForm.arity + arity2;
+            Name n = lambdaForm.names[j];
+            Name n2 = names2[i];
+            if (n != n2) {
+                for (int k = i + 1; k < names2.length; k++) {
+                    names2[k] = names2[k].replaceName(n, n2);
+                }
+            }
+        }
+
+        form = new LambdaForm(lambdaForm.debugName, arity2, names2, result2);
+        return putInCache(key, form);
+    }
+
+    static boolean permutedTypesMatch(int[] reorder, BasicType[] types, Name[] names, int skip) {
+        for (int i = 0; i < reorder.length; i++) {
+            assert (names[skip + i].isParam());
+            assert (names[skip + i].type == types[reorder[i]]);
+        }
+        return true;
+    }
 }
--- a/src/share/classes/java/lang/invoke/MethodHandle.java	Wed Sep 10 18:34:40 2014 +0400
+++ b/src/share/classes/java/lang/invoke/MethodHandle.java	Wed Sep 10 18:34:42 2014 +0400
@@ -864,9 +864,18 @@
      * @see #asCollector
      */
     public MethodHandle asSpreader(Class<?> arrayType, int arrayLength) {
-        asSpreaderChecks(arrayType, arrayLength);
-        int spreadArgPos = type.parameterCount() - arrayLength;
-        return MethodHandleImpl.makeSpreadArguments(this, arrayType, spreadArgPos, arrayLength);
+        MethodType postSpreadType = asSpreaderChecks(arrayType, arrayLength);
+        int arity = type().parameterCount();
+        int spreadArgPos = arity - arrayLength;
+        if (USE_LAMBDA_FORM_EDITOR) {
+            MethodHandle afterSpread = this.asType(postSpreadType);
+            BoundMethodHandle mh = afterSpread.rebind();
+            LambdaForm lform = mh.editor().spreadArgumentsForm(1 + spreadArgPos, arrayType, arrayLength);
+            MethodType preSpreadType = postSpreadType.replaceParameterTypes(spreadArgPos, arity, arrayType);
+            return mh.copyWith(preSpreadType, lform);
+        } else {
+            return MethodHandleImpl.makeSpreadArguments(this, arrayType, spreadArgPos, arrayLength);
+        }
     }
 
     /**
@@ -986,12 +995,24 @@
      */
     public MethodHandle asCollector(Class<?> arrayType, int arrayLength) {
         asCollectorChecks(arrayType, arrayLength);
-        int collectArgPos = type().parameterCount()-1;
-        MethodHandle target = this;
-        if (arrayType != type().parameterType(collectArgPos))
-            target = MethodHandleImpl.makePairwiseConvert(this, type().changeParameterType(collectArgPos, arrayType), true);
-        MethodHandle collector = MethodHandleImpl.varargsArray(arrayType, arrayLength);
-        return MethodHandles.collectArguments(target, collectArgPos, collector);
+        int collectArgPos = type().parameterCount() - 1;
+        if (USE_LAMBDA_FORM_EDITOR) {
+            BoundMethodHandle mh = rebind();
+            MethodType resultType = type().asCollectorType(arrayType, arrayLength);
+            MethodHandle newArray = MethodHandleImpl.varargsArray(arrayType, arrayLength);
+            LambdaForm lform = mh.editor().collectArgumentArrayForm(1 + collectArgPos, newArray);
+            if (lform != null) {
+                return mh.copyWith(resultType, lform);
+            }
+            lform = mh.editor().collectArgumentsForm(1 + collectArgPos, newArray.type().basicType());
+            return mh.copyWithExtendL(resultType, lform, newArray);
+        } else {
+            MethodHandle target = this;
+            if (arrayType != type().parameterType(collectArgPos))
+                target = MethodHandleImpl.makePairwiseConvert(this, type().changeParameterType(collectArgPos, arrayType), true);
+            MethodHandle collector = MethodHandleImpl.varargsArray(arrayType, arrayLength);
+            return MethodHandles.collectArguments(target, collectArgPos, collector);
+        }
     }
 
     /**
--- a/src/share/classes/java/lang/invoke/MethodHandleImpl.java	Wed Sep 10 18:34:40 2014 +0400
+++ b/src/share/classes/java/lang/invoke/MethodHandleImpl.java	Wed Sep 10 18:34:42 2014 +0400
@@ -191,7 +191,11 @@
         assert(dstType.parameterCount() == target.type().parameterCount());
         if (srcType == dstType)
             return target;
-        return makePairwiseConvertIndirect(target, srcType, strict, monobox);
+        if (USE_LAMBDA_FORM_EDITOR) {
+            return makePairwiseConvertByEditor(target, srcType, strict, monobox);
+        } else {
+            return makePairwiseConvertIndirect(target, srcType, strict, monobox);
+        }
     }
 
     private static int countNonNull(Object[] array) {
@@ -202,6 +206,63 @@
         return count;
     }
 
+    static MethodHandle makePairwiseConvertByEditor(MethodHandle target, MethodType srcType,
+                                                    boolean strict, boolean monobox) {
+        Object[] convSpecs = computeValueConversions(srcType, target.type(), strict, monobox);
+        int convCount = countNonNull(convSpecs);
+        if (convCount == 0)
+            return target.viewAsType(srcType, strict);
+        MethodType basicSrcType = srcType.basicType();
+        MethodType midType = target.type().basicType();
+        BoundMethodHandle mh = target.rebind();
+        // FIXME: Reduce number of bindings when there is more than one Class conversion.
+        // FIXME: Reduce number of bindings when there are repeated conversions.
+        for (int i = 0; i < convSpecs.length-1; i++) {
+            Object convSpec = convSpecs[i];
+            if (convSpec == null)  continue;
+            MethodHandle fn;
+            if (convSpec instanceof Class) {
+                fn = Lazy.MH_castReference.bindTo(convSpec);
+            } else {
+                fn = (MethodHandle) convSpec;
+            }
+            Class<?> newType = basicSrcType.parameterType(i);
+            if (--convCount == 0)
+                midType = srcType;
+            else
+                midType = midType.changeParameterType(i, newType);
+            LambdaForm form2 = mh.editor().filterArgumentForm(1+i, BasicType.basicType(newType));
+            mh = mh.copyWithExtendL(midType, form2, fn);
+            mh = mh.rebind();
+        }
+        Object convSpec = convSpecs[convSpecs.length-1];
+        if (convSpec != null) {
+            MethodHandle fn;
+            if (convSpec instanceof Class) {
+                if (convSpec == void.class)
+                    fn = null;
+                else
+                    fn = Lazy.MH_castReference.bindTo(convSpec);
+            } else {
+                fn = (MethodHandle) convSpec;
+            }
+            Class<?> newType = basicSrcType.returnType();
+            assert(--convCount == 0);
+            midType = srcType;
+            if (fn != null) {
+                mh = mh.rebind();  // rebind if too complex
+                LambdaForm form2 = mh.editor().filterReturnForm(BasicType.basicType(newType), false);
+                mh = mh.copyWithExtendL(midType, form2, fn);
+            } else {
+                LambdaForm form2 = mh.editor().filterReturnForm(BasicType.basicType(newType), true);
+                mh = mh.copyWith(midType, form2);
+            }
+        }
+        assert(convCount == 0);
+        assert(mh.type().equals(srcType));
+        return mh;
+    }
+
     static MethodHandle makePairwiseConvertIndirect(MethodHandle target, MethodType srcType,
                                                     boolean strict, boolean monobox) {
         // Calculate extra arguments (temporaries) required in the names array.
--- a/src/share/classes/java/lang/invoke/MethodHandleStatics.java	Wed Sep 10 18:34:40 2014 +0400
+++ b/src/share/classes/java/lang/invoke/MethodHandleStatics.java	Wed Sep 10 18:34:42 2014 +0400
@@ -45,19 +45,21 @@
     static final boolean DUMP_CLASS_FILES;
     static final boolean TRACE_INTERPRETER;
     static final boolean TRACE_METHOD_LINKAGE;
+    static final boolean USE_LAMBDA_FORM_EDITOR;
     static final int COMPILE_THRESHOLD;
     static final int PROFILE_LEVEL;
 
     static {
-        final Object[] values = { false, false, false, false, null, null };
+        final Object[] values = { false, false, false, false, false, null, null };
         AccessController.doPrivileged(new PrivilegedAction<Void>() {
                 public Void run() {
                     values[0] = Boolean.getBoolean("java.lang.invoke.MethodHandle.DEBUG_NAMES");
                     values[1] = Boolean.getBoolean("java.lang.invoke.MethodHandle.DUMP_CLASS_FILES");
                     values[2] = Boolean.getBoolean("java.lang.invoke.MethodHandle.TRACE_INTERPRETER");
                     values[3] = Boolean.getBoolean("java.lang.invoke.MethodHandle.TRACE_METHOD_LINKAGE");
-                    values[4] = Integer.getInteger("java.lang.invoke.MethodHandle.COMPILE_THRESHOLD", 30);
-                    values[5] = Integer.getInteger("java.lang.invoke.MethodHandle.PROFILE_LEVEL", 0);
+                    values[4] = Boolean.getBoolean("java.lang.invoke.MethodHandle.USE_LF_EDITOR");
+                    values[5] = Integer.getInteger("java.lang.invoke.MethodHandle.COMPILE_THRESHOLD", 30);
+                    values[6] = Integer.getInteger("java.lang.invoke.MethodHandle.PROFILE_LEVEL", 0);
                     return null;
                 }
             });
@@ -65,8 +67,9 @@
         DUMP_CLASS_FILES          = (Boolean) values[1];
         TRACE_INTERPRETER         = (Boolean) values[2];
         TRACE_METHOD_LINKAGE      = (Boolean) values[3];
-        COMPILE_THRESHOLD         = (Integer) values[4];
-        PROFILE_LEVEL             = (Integer) values[5];
+        USE_LAMBDA_FORM_EDITOR    = (Boolean) values[4];
+        COMPILE_THRESHOLD         = (Integer) values[5];
+        PROFILE_LEVEL             = (Integer) values[6];
     }
 
     /** Tell if any of the debugging switches are turned on.
--- a/src/share/classes/java/lang/invoke/MethodHandles.java	Wed Sep 10 18:34:40 2014 +0400
+++ b/src/share/classes/java/lang/invoke/MethodHandles.java	Wed Sep 10 18:34:42 2014 +0400
@@ -28,7 +28,6 @@
 import java.lang.reflect.*;
 import java.util.BitSet;
 import java.util.List;
-import java.util.ArrayList;
 import java.util.Arrays;
 
 import sun.invoke.util.ValueConversions;
@@ -2092,23 +2091,86 @@
      */
     public static
     MethodHandle permuteArguments(MethodHandle target, MethodType newType, int... reorder) {
-        reorder = reorder.clone();
-        permuteArgumentChecks(reorder, newType, target.type());
-        // first detect dropped arguments and handle them separately
-        MethodHandle originalTarget = target;
-        int newArity = newType.parameterCount();
-        for (int dropIdx; (dropIdx = findFirstDrop(reorder, newArity)) >= 0; ) {
-            // dropIdx is missing from reorder; add it in at the end
-            int oldArity = reorder.length;
-            target = dropArguments(target, oldArity, newType.parameterType(dropIdx));
-            reorder = Arrays.copyOf(reorder, oldArity+1);
-            reorder[oldArity] = dropIdx;
+        reorder = reorder.clone();  // get a private copy
+        MethodType oldType = target.type();
+        permuteArgumentChecks(reorder, newType, oldType);
+        if (USE_LAMBDA_FORM_EDITOR) {
+            // first detect dropped arguments and handle them separately
+            int[] originalReorder = reorder;
+            BoundMethodHandle result = target.rebind();
+            LambdaForm form = result.form;
+            int newArity = newType.parameterCount();
+            // Normalize the reordering into a real permutation,
+            // by removing duplicates and adding dropped elements.
+            // This somewhat improves lambda form caching, as well
+            // as simplifying the transform by breaking it up into steps.
+            for (int ddIdx; (ddIdx = findFirstDupOrDrop(reorder, newArity)) != 0; ) {
+                if (ddIdx > 0) {
+                    // We found a duplicated entry at reorder[ddIdx].
+                    // Example:  (x,y,z)->asList(x,y,z)
+                    // permuted by [1*,0,1] => (a0,a1)=>asList(a1,a0,a1)
+                    // permuted by [0,1,0*] => (a0,a1)=>asList(a0,a1,a0)
+                    // The starred element corresponds to the argument
+                    // deleted by the dupArgumentForm transform.
+                    int srcPos = ddIdx, dstPos = srcPos, dupVal = reorder[srcPos];
+                    boolean killFirst = false;
+                    for (int val; (val = reorder[--dstPos]) != dupVal; ) {
+                        // Set killFirst if the dup is larger than an intervening position.
+                        // This will remove at least one inversion from the permutation.
+                        if (dupVal > val) killFirst = true;
+                    }
+                    if (!killFirst) {
+                        srcPos = dstPos;
+                        dstPos = ddIdx;
+                    }
+                    form = form.editor().dupArgumentForm(1 + srcPos, 1 + dstPos);
+                    assert (reorder[srcPos] == reorder[dstPos]);
+                    oldType = oldType.dropParameterTypes(dstPos, dstPos + 1);
+                    // contract the reordering by removing the element at dstPos
+                    int tailPos = dstPos + 1;
+                    System.arraycopy(reorder, tailPos, reorder, dstPos, reorder.length - tailPos);
+                    reorder = Arrays.copyOf(reorder, reorder.length - 1);
+                } else {
+                    int dropVal = ~ddIdx, insPos = 0;
+                    while (insPos < reorder.length && reorder[insPos] < dropVal) {
+                        // Find first element of reorder larger than dropVal.
+                        // This is where we will insert the dropVal.
+                        insPos += 1;
+                    }
+                    Class<?> ptype = newType.parameterType(dropVal);
+                    form = form.editor().addArgumentForm(1 + insPos, BasicType.basicType(ptype));
+                    oldType = oldType.insertParameterTypes(insPos, ptype);
+                    // expand the reordering by inserting an element at insPos
+                    int tailPos = insPos + 1;
+                    reorder = Arrays.copyOf(reorder, reorder.length + 1);
+                    System.arraycopy(reorder, insPos, reorder, tailPos, reorder.length - tailPos);
+                    reorder[insPos] = dropVal;
+                }
+                assert (permuteArgumentChecks(reorder, newType, oldType));
+            }
+            assert (reorder.length == newArity);  // a perfect permutation
+            // Note:  This may cache too many distinct LFs. Consider backing off to varargs code.
+            form = form.editor().permuteArgumentsForm(1, reorder);
+            if (newType == result.type() && form == result.internalForm())
+                return result;
+            return result.copyWith(newType, form);
+        } else {
+            // first detect dropped arguments and handle them separately
+            MethodHandle originalTarget = target;
+            int newArity = newType.parameterCount();
+            for (int dropIdx; (dropIdx = findFirstDrop(reorder, newArity)) >= 0; ) {
+                // dropIdx is missing from reorder; add it in at the end
+                int oldArity = reorder.length;
+                target = dropArguments(target, oldArity, newType.parameterType(dropIdx));
+                reorder = Arrays.copyOf(reorder, oldArity+1);
+                reorder[oldArity] = dropIdx;
+            }
+            assert(target == originalTarget || permuteArgumentChecks(reorder, newType, target.type()));
+            // Note:  This may cache too many distinct LFs. Consider backing off to varargs code.
+            BoundMethodHandle result = target.rebind();
+            LambdaForm form = result.form.permuteArguments(1, reorder, basicTypes(newType.parameterList()));
+            return result.copyWith(newType, form);
         }
-        assert(target == originalTarget || permuteArgumentChecks(reorder, newType, target.type()));
-        // Note:  This may cache too many distinct LFs. Consider backing off to varargs code.
-        BoundMethodHandle result = target.rebind();
-        LambdaForm form = result.form.permuteArguments(1, reorder, basicTypes(newType.parameterList()));
-        return result.copyWith(newType, form);
     }
 
     /** Return the first value in [0..newArity-1] that is not present in reorder. */
@@ -2141,6 +2203,52 @@
         return zeroPos;
     }
 
+    /**
+     * Return an indication of any duplicate or omission in reorder.
+     * If the reorder contains a duplicate entry, return the index of the second occurrence.
+     * Otherwise, return ~(n), for the first n in [0..newArity-1] that is not present in reorder.
+     * Otherwise, return zero.
+     * If an element not in [0..newArity-1] is encountered, return reorder.length.
+     */
+    private static int findFirstDupOrDrop(int[] reorder, int newArity) {
+        final int BIT_LIMIT = 63;  // max number of bits in bit mask
+        if (newArity < BIT_LIMIT) {
+            long mask = 0;
+            for (int i = 0; i < reorder.length; i++) {
+                int arg = reorder[i];
+                if (arg >= newArity)  return reorder.length;
+                int bit = 1 << arg;
+                if ((mask & bit) != 0)
+                    return i;  // >0 indicates a dup
+                mask |= bit;
+            }
+            if (mask == (1 << newArity) - 1) {
+                assert(Long.numberOfTrailingZeros(Long.lowestOneBit(~mask)) == newArity);
+                return 0;
+            }
+            // find first zero
+            long zeroBit = Long.lowestOneBit(~mask);
+            int zeroPos = Long.numberOfTrailingZeros(zeroBit);
+            assert(zeroPos < newArity);
+            return ~zeroPos;
+        } else {
+            // same algorithm, different bit set
+            BitSet mask = new BitSet(newArity);
+            for (int i = 0; i < reorder.length; i++) {
+                int arg = reorder[i];
+                if (arg >= newArity)  return reorder.length;
+                if (mask.get(arg))
+                    return i;  // >0 indicates a dup
+                mask.set(arg);
+            }
+            int zeroPos = mask.nextClearBit(0);
+            if (zeroPos == newArity) {
+                return 0;
+            }
+            return ~zeroPos;
+        }
+    }
+
     private static boolean permuteArgumentChecks(int[] reorder, MethodType newType, MethodType oldType) {
         if (newType.returnType() != oldType.returnType())
             throw newIllegalArgumentException("return types do not match",
@@ -2372,7 +2480,14 @@
         if (dropped == 0)  return target;
         BoundMethodHandle result = target.rebind();
         LambdaForm lform = result.form;
-        lform = lform.addArguments(pos, valueTypes);
+        if (USE_LAMBDA_FORM_EDITOR) {
+            int insertFormArg = 1 + pos;
+            for (Class<?> ptype : valueTypes) {
+                lform = lform.editor().addArgumentForm(insertFormArg++, BasicType.basicType(ptype));
+            }
+        } else {
+            lform = lform.addArguments(pos, valueTypes);
+        }
         MethodType newType = oldType.insertParameterTypes(pos, valueTypes);
         result = result.copyWith(newType, lform);
         return result;
@@ -2523,7 +2638,18 @@
     /*non-public*/ static
     MethodHandle filterArgument(MethodHandle target, int pos, MethodHandle filter) {
         filterArgumentChecks(target, pos, filter);
-        return MethodHandleImpl.makeCollectArguments(target, filter, pos, false);
+        if (USE_LAMBDA_FORM_EDITOR) {
+            MethodType targetType = target.type();
+            MethodType filterType = filter.type();
+            BoundMethodHandle result = target.rebind();
+            Class<?> newParamType = filterType.parameterType(0);
+            LambdaForm lform = result.editor().filterArgumentForm(1 + pos, BasicType.basicType(newParamType));
+            MethodType newType = targetType.changeParameterType(pos, newParamType);
+            result = result.copyWithExtendL(newType, lform, filter);
+            return result;
+        } else {
+            return MethodHandleImpl.makeCollectArguments(target, filter, pos, false);
+        }
     }
 
     private static void filterArgumentsCheckArity(MethodHandle target, int pos, MethodHandle[] filters) {
@@ -2649,12 +2775,36 @@
      */
     public static
     MethodHandle collectArguments(MethodHandle target, int pos, MethodHandle filter) {
+        MethodType newType = collectArgumentsChecks(target, pos, filter);
+        if (USE_LAMBDA_FORM_EDITOR) {
+            MethodType collectorType = filter.type();
+            BoundMethodHandle result = target.rebind();
+            LambdaForm lform;
+            if (collectorType.returnType().isArray() && filter.intrinsicName() == Intrinsic.NEW_ARRAY) {
+                lform = result.editor().collectArgumentArrayForm(1 + pos, filter);
+                if (lform != null) {
+                    return result.copyWith(newType, lform);
+                }
+            }
+            lform = result.editor().collectArgumentsForm(1 + pos, collectorType.basicType());
+            return result.copyWithExtendL(newType, lform, filter);
+        } else {
+            return MethodHandleImpl.makeCollectArguments(target, filter, pos, false);
+        }
+    }
+
+    private static MethodType collectArgumentsChecks(MethodHandle target, int pos, MethodHandle filter) throws RuntimeException {
         MethodType targetType = target.type();
         MethodType filterType = filter.type();
-        if (filterType.returnType() != void.class &&
-            filterType.returnType() != targetType.parameterType(pos))
+        Class<?> rtype = filterType.returnType();
+        List<Class<?>> filterArgs = filterType.parameterList();
+        if (rtype == void.class) {
+            return targetType.insertParameterTypes(pos, filterArgs);
+        }
+        if (rtype != targetType.parameterType(pos)) {
             throw newIllegalArgumentException("target and filter types do not match", targetType, filterType);
-        return MethodHandleImpl.makeCollectArguments(target, filter, pos, false);
+        }
+        return targetType.dropParameterTypes(pos, pos+1).insertParameterTypes(pos, filterArgs);
     }
 
     /**
@@ -2719,7 +2869,16 @@
         MethodType targetType = target.type();
         MethodType filterType = filter.type();
         filterReturnValueChecks(targetType, filterType);
-        return MethodHandleImpl.makeCollectArguments(filter, target, 0, false);
+        if (USE_LAMBDA_FORM_EDITOR) {
+            BoundMethodHandle result = target.rebind();
+            BasicType rtype = BasicType.basicType(filterType.returnType());
+            LambdaForm lform = result.editor().filterReturnForm(rtype, false);
+            MethodType newType = targetType.changeReturnType(filterType.returnType());
+            result = result.copyWithExtendL(newType, lform, filter);
+            return result;
+        } else {
+            return MethodHandleImpl.makeCollectArguments(filter, target, 0, false);
+        }
     }
 
     private static void filterReturnValueChecks(MethodType targetType, MethodType filterType) throws RuntimeException {
@@ -2813,7 +2972,19 @@
         MethodType targetType = target.type();
         MethodType combinerType = combiner.type();
         Class<?> rtype = foldArgumentChecks(foldPos, targetType, combinerType);
-        return MethodHandleImpl.makeCollectArguments(target, combiner, foldPos, true);
+        if (USE_LAMBDA_FORM_EDITOR) {
+            BoundMethodHandle result = target.rebind();
+            boolean dropResult = (rtype == void.class);
+            // Note:  This may cache too many distinct LFs. Consider backing off to varargs code.
+            LambdaForm lform = result.editor().foldArgumentsForm(1 + foldPos, dropResult, combinerType.basicType());
+            MethodType newType = targetType;
+            if (!dropResult)
+                newType = newType.dropParameterTypes(foldPos, foldPos + 1);
+            result = result.copyWithExtendL(newType, lform, combiner);
+            return result;
+        } else {
+            return MethodHandleImpl.makeCollectArguments(target, combiner, foldPos, true);
+        }
     }
 
     private static Class<?> foldArgumentChecks(int foldPos, MethodType targetType, MethodType combinerType) {