src/java.base/share/classes/java/lang/invoke/MethodHandles.java
Index Unified diffs Context diffs Sdiffs Patch New Old Previous File Next File
*** old/src/java.base/share/classes/java/lang/invoke/MethodHandles.java	Tue Sep  9 17:35:35 2014
--- new/src/java.base/share/classes/java/lang/invoke/MethodHandles.java	Tue Sep  9 17:35:35 2014

*** 26,36 **** --- 26,35 ---- package java.lang.invoke; 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; import sun.invoke.util.VerifyAccess; import sun.invoke.util.Wrapper;
*** 2092,2103 **** --- 2091,2164 ---- * 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) { ! reorder = reorder.clone(); // get a private copy ! permuteArgumentChecks(reorder, newType, target.type()); ! 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
*** 2110,2119 **** --- 2171,2181 ---- // 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. */ private static int findFirstDrop(int[] reorder, int newArity) { final int BIT_LIMIT = 63; // max number of bits in bit mask if (newArity < BIT_LIMIT) {
*** 2141,2150 **** --- 2203,2258 ---- if (zeroPos == newArity) return -1; 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", oldType, newType); if (reorder.length == oldType.parameterCount()) {
*** 2372,2382 **** --- 2480,2497 ---- MethodType oldType = target.type(); // get NPE int dropped = dropArgumentChecks(oldType, pos, valueTypes); if (dropped == 0) return target; BoundMethodHandle result = target.rebind(); LambdaForm lform = result.form; + 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,2534 **** --- 2638,2660 ---- } /*non-public*/ static MethodHandle filterArgument(MethodHandle target, int pos, MethodHandle filter) { filterArgumentChecks(target, pos, filter); + 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) { MethodType targetType = target.type(); int maxPos = targetType.parameterCount(); if (pos + filters.length > maxPos)
*** 2649,2664 **** --- 2775,2814 ---- * @see MethodHandles#filterArguments * @see MethodHandles#filterReturnValue */ 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); } /** * Adapts a target method handle by post-processing * its return value (if any) with a filter (another method handle).
*** 2719,2730 **** --- 2869,2889 ---- public static MethodHandle filterReturnValue(MethodHandle target, MethodHandle filter) { MethodType targetType = target.type(); MethodType filterType = filter.type(); filterReturnValueChecks(targetType, filterType); + 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 { Class<?> rtype = targetType.returnType(); int filterValues = filterType.parameterCount(); if (filterValues == 0
*** 2813,2824 **** --- 2972,2995 ---- MethodHandle foldArguments(MethodHandle target, MethodHandle combiner) { int foldPos = 0; MethodType targetType = target.type(); MethodType combinerType = combiner.type(); Class<?> rtype = foldArgumentChecks(foldPos, targetType, combinerType); + 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) { int foldArgs = combinerType.parameterCount(); Class<?> rtype = combinerType.returnType(); int foldVals = rtype == void.class ? 0 : 1;

src/java.base/share/classes/java/lang/invoke/MethodHandles.java
Index Unified diffs Context diffs Sdiffs Patch New Old Previous File Next File