27 |
27 |
28 import sun.invoke.util.VerifyType; |
28 import sun.invoke.util.VerifyType; |
29 import sun.invoke.util.Wrapper; |
29 import sun.invoke.util.Wrapper; |
30 import sun.invoke.util.ValueConversions; |
30 import sun.invoke.util.ValueConversions; |
31 import java.util.Arrays; |
31 import java.util.Arrays; |
|
32 import java.util.ArrayList; |
|
33 import java.util.Collections; |
32 import static java.lang.invoke.MethodHandleNatives.Constants.*; |
34 import static java.lang.invoke.MethodHandleNatives.Constants.*; |
33 import static java.lang.invoke.MethodHandleStatics.*; |
35 import static java.lang.invoke.MethodHandleStatics.*; |
34 |
36 |
35 /** |
37 /** |
36 * This method handle performs simple conversion or checking of a single argument. |
38 * This method handle performs simple conversion or checking of a single argument. |
60 |
62 |
61 // TO DO: When adapting another MH with a null conversion, clone |
63 // TO DO: When adapting another MH with a null conversion, clone |
62 // the target and change its type, instead of adding another layer. |
64 // the target and change its type, instead of adding another layer. |
63 |
65 |
64 /** Can a JVM-level adapter directly implement the proposed |
66 /** Can a JVM-level adapter directly implement the proposed |
65 * argument conversions, as if by MethodHandles.convertArguments? |
67 * argument conversions, as if by fixed-arity MethodHandle.asType? |
66 */ |
68 */ |
67 static boolean canPairwiseConvert(MethodType newType, MethodType oldType, int level) { |
69 static boolean canPairwiseConvert(MethodType newType, MethodType oldType, int level) { |
68 // same number of args, of course |
70 // same number of args, of course |
69 int len = newType.parameterCount(); |
71 int len = newType.parameterCount(); |
70 if (len != oldType.parameterCount()) |
72 if (len != oldType.parameterCount()) |
90 |
92 |
91 return true; |
93 return true; |
92 } |
94 } |
93 |
95 |
94 /** Can a JVM-level adapter directly implement the proposed |
96 /** Can a JVM-level adapter directly implement the proposed |
95 * argument conversion, as if by MethodHandles.convertArguments? |
97 * argument conversion, as if by fixed-arity MethodHandle.asType? |
96 */ |
98 */ |
97 static boolean canConvertArgument(Class<?> src, Class<?> dst, int level) { |
99 static boolean canConvertArgument(Class<?> src, Class<?> dst, int level) { |
98 // ? Retool this logic to use RETYPE_ONLY, CHECK_CAST, etc., as opcodes, |
100 // ? Retool this logic to use RETYPE_ONLY, CHECK_CAST, etc., as opcodes, |
99 // so we don't need to repeat so much decision making. |
101 // so we don't need to repeat so much decision making. |
100 if (VerifyType.isNullConversion(src, dst)) { |
102 if (VerifyType.isNullConversion(src, dst)) { |
548 static MethodHandle makeVarargsCollector(MethodHandle target, Class<?> arrayType) { |
550 static MethodHandle makeVarargsCollector(MethodHandle target, Class<?> arrayType) { |
549 MethodType type = target.type(); |
551 MethodType type = target.type(); |
550 int last = type.parameterCount() - 1; |
552 int last = type.parameterCount() - 1; |
551 if (type.parameterType(last) != arrayType) |
553 if (type.parameterType(last) != arrayType) |
552 target = target.asType(type.changeParameterType(last, arrayType)); |
554 target = target.asType(type.changeParameterType(last, arrayType)); |
|
555 target = target.asFixedArity(); // make sure this attribute is turned off |
553 return new AsVarargsCollector(target, arrayType); |
556 return new AsVarargsCollector(target, arrayType); |
554 } |
557 } |
555 |
558 |
556 static class AsVarargsCollector extends AdapterMethodHandle { |
559 static class AsVarargsCollector extends AdapterMethodHandle { |
557 final MethodHandle target; |
560 final MethodHandle target; |
592 throw new WrongMethodTypeException("cannot build collector"); |
600 throw new WrongMethodTypeException("cannot build collector"); |
593 } |
601 } |
594 cache = collector; |
602 cache = collector; |
595 return collector.asType(newType); |
603 return collector.asType(newType); |
596 } |
604 } |
597 |
|
598 @Override |
|
599 public MethodHandle asVarargsCollector(Class<?> arrayType) { |
|
600 MethodType type = this.type(); |
|
601 if (type.parameterType(type.parameterCount()-1) == arrayType) |
|
602 return this; |
|
603 return super.asVarargsCollector(arrayType); |
|
604 } |
|
605 } |
605 } |
606 |
606 |
607 /** Can a checkcast adapter validly convert the target to newType? |
607 /** Can a checkcast adapter validly convert the target to newType? |
608 * The JVM supports all kind of reference casts, even silly ones. |
608 * The JVM supports all kind of reference casts, even silly ones. |
609 */ |
609 */ |
745 Class<?> boxType = Wrapper.asWrapperType(convType); |
745 Class<?> boxType = Wrapper.asWrapperType(convType); |
746 Class<?> primType = Wrapper.asPrimitiveType(convType); |
746 Class<?> primType = Wrapper.asPrimitiveType(convType); |
747 if (!canUnboxArgument(newType, oldType, arg, convType, level)) |
747 if (!canUnboxArgument(newType, oldType, arg, convType, level)) |
748 return null; |
748 return null; |
749 MethodType castDone = newType; |
749 MethodType castDone = newType; |
750 if (!VerifyType.isNullConversion(src, boxType)) |
750 if (!VerifyType.isNullConversion(src, boxType)) { |
|
751 // Examples: Object->int, Number->int, Comparable->int; Byte->int, Character->int |
|
752 if (level != 0) { |
|
753 // must include additional conversions |
|
754 if (src == Object.class || !Wrapper.isWrapperType(src)) { |
|
755 // src must be examined at runtime, to detect Byte, Character, etc. |
|
756 MethodHandle unboxMethod = (level == 1 |
|
757 ? ValueConversions.unbox(dst) |
|
758 : ValueConversions.unboxCast(dst)); |
|
759 long conv = makeConv(OP_COLLECT_ARGS, arg, basicType(src), basicType(dst)); |
|
760 return new AdapterMethodHandle(target, newType, conv, unboxMethod); |
|
761 } |
|
762 // Example: Byte->int |
|
763 // Do this by reformulating the problem to Byte->byte. |
|
764 Class<?> srcPrim = Wrapper.forWrapperType(src).primitiveType(); |
|
765 MethodType midType = newType.changeParameterType(arg, srcPrim); |
|
766 MethodHandle fixPrim; // makePairwiseConvert(midType, target, 0); |
|
767 if (canPrimCast(midType, oldType, arg, dst)) |
|
768 fixPrim = makePrimCast(midType, target, arg, dst); |
|
769 else |
|
770 fixPrim = target; |
|
771 return makeUnboxArgument(newType, fixPrim, arg, srcPrim, 0); |
|
772 } |
751 castDone = newType.changeParameterType(arg, boxType); |
773 castDone = newType.changeParameterType(arg, boxType); |
|
774 } |
752 long conv = makeConv(OP_REF_TO_PRIM, arg, T_OBJECT, basicType(primType)); |
775 long conv = makeConv(OP_REF_TO_PRIM, arg, T_OBJECT, basicType(primType)); |
753 MethodHandle adapter = new AdapterMethodHandle(target, castDone, conv, boxType); |
776 MethodHandle adapter = new AdapterMethodHandle(target, castDone, conv, boxType); |
754 if (castDone == newType) |
777 if (castDone == newType) |
755 return adapter; |
778 return adapter; |
756 return makeCheckCast(newType, adapter, arg, boxType); |
779 return makeCheckCast(newType, adapter, arg, boxType); |
915 static MethodHandle makeSwapArguments(MethodType newType, MethodHandle target, |
938 static MethodHandle makeSwapArguments(MethodType newType, MethodHandle target, |
916 int swapArg1, int swapArg2) { |
939 int swapArg1, int swapArg2) { |
917 if (swapArg1 == swapArg2) |
940 if (swapArg1 == swapArg2) |
918 return target; |
941 return target; |
919 if (swapArg1 > swapArg2) { int t = swapArg1; swapArg1 = swapArg2; swapArg2 = t; } |
942 if (swapArg1 > swapArg2) { int t = swapArg1; swapArg1 = swapArg2; swapArg2 = t; } |
|
943 if (type2size(newType.parameterType(swapArg1)) != |
|
944 type2size(newType.parameterType(swapArg2))) { |
|
945 // turn a swap into a pair of rotates: |
|
946 // [x a b c y] => [a b c y x] => [y a b c x] |
|
947 int argc = swapArg2 - swapArg1 + 1; |
|
948 final int ROT = 1; |
|
949 ArrayList<Class<?>> rot1Params = new ArrayList<Class<?>>(target.type().parameterList()); |
|
950 Collections.rotate(rot1Params.subList(swapArg1, swapArg1 + argc), -ROT); |
|
951 MethodType rot1Type = MethodType.methodType(target.type().returnType(), rot1Params); |
|
952 MethodHandle rot1 = makeRotateArguments(rot1Type, target, swapArg1, argc, +ROT); |
|
953 if (argc == 2) return rot1; |
|
954 MethodHandle rot2 = makeRotateArguments(newType, rot1, swapArg1, argc-1, -ROT); |
|
955 return rot2; |
|
956 } |
920 if (!canSwapArguments(newType, target.type(), swapArg1, swapArg2)) |
957 if (!canSwapArguments(newType, target.type(), swapArg1, swapArg2)) |
921 return null; |
958 return null; |
922 Class<?> swapType = newType.parameterType(swapArg1); |
959 Class<?> swapType = newType.parameterType(swapArg1); |
923 // in arglist: [0: ...keep1 | pos1: a1 | pos1+1: keep2... | pos2: a2 | pos2+1: keep3... ] |
960 // in arglist: [0: ...keep1 | pos1: a1 | pos1+1: keep2... | pos2: a2 | pos2+1: keep3... ] |
924 // out arglist: [0: ...keep1 | pos1: a2 | pos1+1: keep2... | pos2: a1 | pos2+1: keep3... ] |
961 // out arglist: [0: ...keep1 | pos1: a2 | pos1+1: keep2... | pos2: a1 | pos2+1: keep3... ] |
944 |
981 |
945 /** Can an adapter rotate arguments to convert the target to newType? */ |
982 /** Can an adapter rotate arguments to convert the target to newType? */ |
946 static boolean canRotateArguments(MethodType newType, MethodType targetType, |
983 static boolean canRotateArguments(MethodType newType, MethodType targetType, |
947 int firstArg, int argCount, int rotateBy) { |
984 int firstArg, int argCount, int rotateBy) { |
948 if (!convOpSupported(OP_ROT_ARGS)) return false; |
985 if (!convOpSupported(OP_ROT_ARGS)) return false; |
949 if (argCount <= 2) return false; // must be a swap, not a rotate |
|
950 rotateBy = positiveRotation(argCount, rotateBy); |
986 rotateBy = positiveRotation(argCount, rotateBy); |
951 if (rotateBy == 0) return false; // no rotation |
987 if (rotateBy == 0) return false; // no rotation |
952 if (rotateBy > MAX_ARG_ROTATION && rotateBy < argCount - MAX_ARG_ROTATION) |
988 if (rotateBy > MAX_ARG_ROTATION && rotateBy < argCount - MAX_ARG_ROTATION) |
953 return false; // too many argument positions |
989 return false; // too many argument positions |
954 // Rotate incoming args right N to the out args, N in 1..(argCouunt-1). |
990 // Rotate incoming args right N to the out args, N in 1..(argCouunt-1). |
990 int chunk1Slots = depth0 - depth1; assert(chunk1Slots > 0); |
1026 int chunk1Slots = depth0 - depth1; assert(chunk1Slots > 0); |
991 int chunk2Slots = depth1 - depth2; assert(chunk2Slots > 0); |
1027 int chunk2Slots = depth1 - depth2; assert(chunk2Slots > 0); |
992 // From here on out, it assumes a single-argument shift. |
1028 // From here on out, it assumes a single-argument shift. |
993 assert(MAX_ARG_ROTATION == 1); |
1029 assert(MAX_ARG_ROTATION == 1); |
994 int srcArg, dstArg; |
1030 int srcArg, dstArg; |
|
1031 int dstSlot; |
995 byte basicType; |
1032 byte basicType; |
996 if (chunk2Slots <= chunk1Slots) { |
1033 if (chunk2Slots <= chunk1Slots) { |
997 // Rotate right/down N (rotateBy = +N, N small, c2 small): |
1034 // Rotate right/down N (rotateBy = +N, N small, c2 small): |
998 // in arglist: [0: ...keep1 | arg1: c1... | limit-N: c2 | limit: keep2... ] |
1035 // in arglist: [0: ...keep1 | arg1: c1... | limit-N: c2 | limit: keep2... ] |
999 // out arglist: [0: ...keep1 | arg1: c2 | arg1+N: c1... | limit: keep2... ] |
1036 // out arglist: [0: ...keep1 | arg1: c2 | arg1+N: c1... | limit: keep2... ] |
1000 srcArg = limit-1; |
1037 srcArg = limit-1; |
1001 dstArg = firstArg; |
1038 dstArg = firstArg; |
|
1039 dstSlot = depth0 - chunk2Slots; |
1002 basicType = basicType(newType.parameterType(srcArg)); |
1040 basicType = basicType(newType.parameterType(srcArg)); |
1003 assert(chunk2Slots == type2size(basicType)); |
1041 assert(chunk2Slots == type2size(basicType)); |
1004 } else { |
1042 } else { |
1005 // Rotate left/up N (rotateBy = -N, N small, c1 small): |
1043 // Rotate left/up N (rotateBy = -N, N small, c1 small): |
1006 // in arglist: [0: ...keep1 | arg1: c1 | arg1+N: c2... | limit: keep2... ] |
1044 // in arglist: [0: ...keep1 | arg1: c1 | arg1+N: c2... | limit: keep2... ] |
1007 // out arglist: [0: ...keep1 | arg1: c2 ... | limit-N: c1 | limit: keep2... ] |
1045 // out arglist: [0: ...keep1 | arg1: c2 ... | limit-N: c1 | limit: keep2... ] |
1008 srcArg = firstArg; |
1046 srcArg = firstArg; |
1009 dstArg = limit-1; |
1047 dstArg = limit-1; |
|
1048 dstSlot = depth2; |
1010 basicType = basicType(newType.parameterType(srcArg)); |
1049 basicType = basicType(newType.parameterType(srcArg)); |
1011 assert(chunk1Slots == type2size(basicType)); |
1050 assert(chunk1Slots == type2size(basicType)); |
1012 } |
1051 } |
1013 int dstSlot = newType.parameterSlotDepth(dstArg + 1); |
|
1014 long conv = makeSwapConv(OP_ROT_ARGS, srcArg, basicType, dstSlot); |
1052 long conv = makeSwapConv(OP_ROT_ARGS, srcArg, basicType, dstSlot); |
1015 return new AdapterMethodHandle(target, newType, conv); |
1053 return new AdapterMethodHandle(target, newType, conv); |
1016 } |
1054 } |
1017 |
1055 |
1018 /** Can an adapter spread an argument to convert the target to newType? */ |
1056 /** Can an adapter spread an argument to convert the target to newType? */ |