--- 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<Class<?>> rot1Params = new ArrayList<Class<?>>(target.type().parameterList());
+ Collections.rotate(rot1Params.subList(swapArg1, swapArg1 + argc), -ROT);
+ MethodType rot1Type = MethodType.methodType(target.type().returnType(), rot1Params);
+ MethodHandle rot1 = makeRotateArguments(rot1Type, target, swapArg1, argc, +ROT);
+ if (argc == 2) return rot1;
+ MethodHandle rot2 = makeRotateArguments(newType, rot1, swapArg1, argc-1, -ROT);
+ return rot2;
+ }
if (!canSwapArguments(newType, target.type(), swapArg1, swapArg2))
return null;
Class<?> swapType = newType.parameterType(swapArg1);
@@ -946,7 +983,6 @@
static boolean canRotateArguments(MethodType newType, MethodType targetType,
int firstArg, int argCount, int rotateBy) {
if (!convOpSupported(OP_ROT_ARGS)) return false;
- if (argCount <= 2) return false; // must be a swap, not a rotate
rotateBy = positiveRotation(argCount, rotateBy);
if (rotateBy == 0) return false; // no rotation
if (rotateBy > MAX_ARG_ROTATION && rotateBy < argCount - MAX_ARG_ROTATION)
@@ -992,6 +1028,7 @@
// From here on out, it assumes a single-argument shift.
assert(MAX_ARG_ROTATION == 1);
int srcArg, dstArg;
+ int dstSlot;
byte basicType;
if (chunk2Slots <= chunk1Slots) {
// Rotate right/down N (rotateBy = +N, N small, c2 small):
@@ -999,6 +1036,7 @@
// out arglist: [0: ...keep1 | arg1: c2 | arg1+N: c1... | limit: keep2... ]
srcArg = limit-1;
dstArg = firstArg;
+ dstSlot = depth0 - chunk2Slots;
basicType = basicType(newType.parameterType(srcArg));
assert(chunk2Slots == type2size(basicType));
} else {
@@ -1007,10 +1045,10 @@
// out arglist: [0: ...keep1 | arg1: c2 ... | limit-N: c1 | limit: keep2... ]
srcArg = firstArg;
dstArg = limit-1;
+ dstSlot = depth2;
basicType = basicType(newType.parameterType(srcArg));
assert(chunk1Slots == type2size(basicType));
}
- int dstSlot = newType.parameterSlotDepth(dstArg + 1);
long conv = makeSwapConv(OP_ROT_ARGS, srcArg, basicType, dstSlot);
return new AdapterMethodHandle(target, newType, conv);
}