diff -r d0f7a3e441c4 -r 88ab34b6da6d jdk/src/share/classes/java/lang/invoke/AdapterMethodHandle.java --- a/jdk/src/share/classes/java/lang/invoke/AdapterMethodHandle.java Tue May 17 19:48:19 2011 -0700 +++ b/jdk/src/share/classes/java/lang/invoke/AdapterMethodHandle.java Thu May 26 17:37:36 2011 -0700 @@ -29,6 +29,8 @@ import sun.invoke.util.Wrapper; import sun.invoke.util.ValueConversions; import java.util.Arrays; +import java.util.ArrayList; +import java.util.Collections; import static java.lang.invoke.MethodHandleNatives.Constants.*; import static java.lang.invoke.MethodHandleStatics.*; @@ -62,7 +64,7 @@ // the target and change its type, instead of adding another layer. /** Can a JVM-level adapter directly implement the proposed - * argument conversions, as if by MethodHandles.convertArguments? + * argument conversions, as if by fixed-arity MethodHandle.asType? */ static boolean canPairwiseConvert(MethodType newType, MethodType oldType, int level) { // same number of args, of course @@ -92,7 +94,7 @@ } /** Can a JVM-level adapter directly implement the proposed - * argument conversion, as if by MethodHandles.convertArguments? + * argument conversion, as if by fixed-arity MethodHandle.asType? */ static boolean canConvertArgument(Class src, Class dst, int level) { // ? Retool this logic to use RETYPE_ONLY, CHECK_CAST, etc., as opcodes, @@ -550,6 +552,7 @@ int last = type.parameterCount() - 1; if (type.parameterType(last) != arrayType) target = target.asType(type.changeParameterType(last, arrayType)); + target = target.asFixedArity(); // make sure this attribute is turned off return new AsVarargsCollector(target, arrayType); } @@ -571,6 +574,11 @@ } @Override + public MethodHandle asFixedArity() { + return target; + } + + @Override public MethodHandle asType(MethodType newType) { MethodType type = this.type(); int collectArg = type.parameterCount() - 1; @@ -594,14 +602,6 @@ cache = collector; return collector.asType(newType); } - - @Override - public MethodHandle asVarargsCollector(Class arrayType) { - MethodType type = this.type(); - if (type.parameterType(type.parameterCount()-1) == arrayType) - return this; - return super.asVarargsCollector(arrayType); - } } /** Can a checkcast adapter validly convert the target to newType? @@ -747,8 +747,31 @@ if (!canUnboxArgument(newType, oldType, arg, convType, level)) return null; MethodType castDone = newType; - if (!VerifyType.isNullConversion(src, boxType)) + if (!VerifyType.isNullConversion(src, boxType)) { + // Examples: Object->int, Number->int, Comparable->int; Byte->int, Character->int + if (level != 0) { + // must include additional conversions + if (src == Object.class || !Wrapper.isWrapperType(src)) { + // src must be examined at runtime, to detect Byte, Character, etc. + MethodHandle unboxMethod = (level == 1 + ? ValueConversions.unbox(dst) + : ValueConversions.unboxCast(dst)); + long conv = makeConv(OP_COLLECT_ARGS, arg, basicType(src), basicType(dst)); + return new AdapterMethodHandle(target, newType, conv, unboxMethod); + } + // Example: Byte->int + // Do this by reformulating the problem to Byte->byte. + Class srcPrim = Wrapper.forWrapperType(src).primitiveType(); + MethodType midType = newType.changeParameterType(arg, srcPrim); + MethodHandle fixPrim; // makePairwiseConvert(midType, target, 0); + if (canPrimCast(midType, oldType, arg, dst)) + fixPrim = makePrimCast(midType, target, arg, dst); + else + fixPrim = target; + return makeUnboxArgument(newType, fixPrim, arg, srcPrim, 0); + } castDone = newType.changeParameterType(arg, boxType); + } long conv = makeConv(OP_REF_TO_PRIM, arg, T_OBJECT, basicType(primType)); MethodHandle adapter = new AdapterMethodHandle(target, castDone, conv, boxType); if (castDone == newType) @@ -917,6 +940,20 @@ if (swapArg1 == swapArg2) return target; if (swapArg1 > swapArg2) { int t = swapArg1; swapArg1 = swapArg2; swapArg2 = t; } + if (type2size(newType.parameterType(swapArg1)) != + type2size(newType.parameterType(swapArg2))) { + // turn a swap into a pair of rotates: + // [x a b c y] => [a b c y x] => [y a b c x] + int argc = swapArg2 - swapArg1 + 1; + final int ROT = 1; + ArrayList> rot1Params = new ArrayList>(target.type().parameterList()); + Collections.rotate(rot1Params.subList(swapArg1, swapArg1 + argc), -ROT); + MethodType rot1Type = MethodType.methodType(target.type().returnType(), rot1Params); + MethodHandle rot1 = makeRotateArguments(rot1Type, target, swapArg1, argc, +ROT); + if (argc == 2) return rot1; + MethodHandle rot2 = makeRotateArguments(newType, rot1, swapArg1, argc-1, -ROT); + return rot2; + } if (!canSwapArguments(newType, target.type(), swapArg1, swapArg2)) return null; Class swapType = newType.parameterType(swapArg1); @@ -946,7 +983,6 @@ static boolean canRotateArguments(MethodType newType, MethodType targetType, int firstArg, int argCount, int rotateBy) { if (!convOpSupported(OP_ROT_ARGS)) return false; - if (argCount <= 2) return false; // must be a swap, not a rotate rotateBy = positiveRotation(argCount, rotateBy); if (rotateBy == 0) return false; // no rotation if (rotateBy > MAX_ARG_ROTATION && rotateBy < argCount - MAX_ARG_ROTATION) @@ -992,6 +1028,7 @@ // From here on out, it assumes a single-argument shift. assert(MAX_ARG_ROTATION == 1); int srcArg, dstArg; + int dstSlot; byte basicType; if (chunk2Slots <= chunk1Slots) { // Rotate right/down N (rotateBy = +N, N small, c2 small): @@ -999,6 +1036,7 @@ // out arglist: [0: ...keep1 | arg1: c2 | arg1+N: c1... | limit: keep2... ] srcArg = limit-1; dstArg = firstArg; + dstSlot = depth0 - chunk2Slots; basicType = basicType(newType.parameterType(srcArg)); assert(chunk2Slots == type2size(basicType)); } else { @@ -1007,10 +1045,10 @@ // out arglist: [0: ...keep1 | arg1: c2 ... | limit-N: c1 | limit: keep2... ] srcArg = firstArg; dstArg = limit-1; + dstSlot = depth2; basicType = basicType(newType.parameterType(srcArg)); assert(chunk1Slots == type2size(basicType)); } - int dstSlot = newType.parameterSlotDepth(dstArg + 1); long conv = makeSwapConv(OP_ROT_ARGS, srcArg, basicType, dstSlot); return new AdapterMethodHandle(target, newType, conv); }