806 |
759 |
807 private static String capitalize(String x) { |
760 private static String capitalize(String x) { |
808 return Character.toUpperCase(x.charAt(0))+x.substring(1); |
761 return Character.toUpperCase(x.charAt(0))+x.substring(1); |
809 } |
762 } |
810 |
763 |
811 /// Collection of multiple arguments. |
|
812 |
|
813 public static Object convertArrayElements(Class<?> arrayType, Object array) { |
|
814 Class<?> src = array.getClass().getComponentType(); |
|
815 Class<?> dst = arrayType.getComponentType(); |
|
816 if (src == null || dst == null) throw new IllegalArgumentException("not array type"); |
|
817 Wrapper sw = (src.isPrimitive() ? Wrapper.forPrimitiveType(src) : null); |
|
818 Wrapper dw = (dst.isPrimitive() ? Wrapper.forPrimitiveType(dst) : null); |
|
819 int length; |
|
820 if (sw == null) { |
|
821 Object[] a = (Object[]) array; |
|
822 length = a.length; |
|
823 if (dw == null) |
|
824 return Arrays.copyOf(a, length, arrayType.asSubclass(Object[].class)); |
|
825 Object res = dw.makeArray(length); |
|
826 dw.copyArrayUnboxing(a, 0, res, 0, length); |
|
827 return res; |
|
828 } |
|
829 length = java.lang.reflect.Array.getLength(array); |
|
830 Object[] res; |
|
831 if (dw == null) { |
|
832 res = Arrays.copyOf(NO_ARGS_ARRAY, length, arrayType.asSubclass(Object[].class)); |
|
833 } else { |
|
834 res = new Object[length]; |
|
835 } |
|
836 sw.copyArrayBoxing(array, 0, res, 0, length); |
|
837 if (dw == null) return res; |
|
838 Object a = dw.makeArray(length); |
|
839 dw.copyArrayUnboxing(res, 0, a, 0, length); |
|
840 return a; |
|
841 } |
|
842 |
|
843 private static MethodHandle findCollector(String name, int nargs, Class<?> rtype, Class<?>... ptypes) { |
|
844 MethodType type = MethodType.genericMethodType(nargs) |
|
845 .changeReturnType(rtype) |
|
846 .insertParameterTypes(0, ptypes); |
|
847 try { |
|
848 return IMPL_LOOKUP.findStatic(THIS_CLASS, name, type); |
|
849 } catch (ReflectiveOperationException ex) { |
|
850 return null; |
|
851 } |
|
852 } |
|
853 |
|
854 private static final Object[] NO_ARGS_ARRAY = {}; |
|
855 private static Object[] makeArray(Object... args) { return args; } |
|
856 private static Object[] array() { return NO_ARGS_ARRAY; } |
|
857 private static Object[] array(Object a0) |
|
858 { return makeArray(a0); } |
|
859 private static Object[] array(Object a0, Object a1) |
|
860 { return makeArray(a0, a1); } |
|
861 private static Object[] array(Object a0, Object a1, Object a2) |
|
862 { return makeArray(a0, a1, a2); } |
|
863 private static Object[] array(Object a0, Object a1, Object a2, Object a3) |
|
864 { return makeArray(a0, a1, a2, a3); } |
|
865 private static Object[] array(Object a0, Object a1, Object a2, Object a3, |
|
866 Object a4) |
|
867 { return makeArray(a0, a1, a2, a3, a4); } |
|
868 private static Object[] array(Object a0, Object a1, Object a2, Object a3, |
|
869 Object a4, Object a5) |
|
870 { return makeArray(a0, a1, a2, a3, a4, a5); } |
|
871 private static Object[] array(Object a0, Object a1, Object a2, Object a3, |
|
872 Object a4, Object a5, Object a6) |
|
873 { return makeArray(a0, a1, a2, a3, a4, a5, a6); } |
|
874 private static Object[] array(Object a0, Object a1, Object a2, Object a3, |
|
875 Object a4, Object a5, Object a6, Object a7) |
|
876 { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7); } |
|
877 private static Object[] array(Object a0, Object a1, Object a2, Object a3, |
|
878 Object a4, Object a5, Object a6, Object a7, |
|
879 Object a8) |
|
880 { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8); } |
|
881 private static Object[] array(Object a0, Object a1, Object a2, Object a3, |
|
882 Object a4, Object a5, Object a6, Object a7, |
|
883 Object a8, Object a9) |
|
884 { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } |
|
885 private static MethodHandle[] makeArrays() { |
|
886 ArrayList<MethodHandle> mhs = new ArrayList<>(); |
|
887 for (;;) { |
|
888 MethodHandle mh = findCollector("array", mhs.size(), Object[].class); |
|
889 if (mh == null) break; |
|
890 mhs.add(mh); |
|
891 } |
|
892 assert(mhs.size() == 11); // current number of methods |
|
893 return mhs.toArray(new MethodHandle[MAX_ARITY+1]); |
|
894 } |
|
895 private static final MethodHandle[] ARRAYS = makeArrays(); |
|
896 |
|
897 // filling versions of the above: |
|
898 // using Integer len instead of int len and no varargs to avoid bootstrapping problems |
|
899 private static Object[] fillNewArray(Integer len, Object[] /*not ...*/ args) { |
|
900 Object[] a = new Object[len]; |
|
901 fillWithArguments(a, 0, args); |
|
902 return a; |
|
903 } |
|
904 private static Object[] fillNewTypedArray(Object[] example, Integer len, Object[] /*not ...*/ args) { |
|
905 Object[] a = Arrays.copyOf(example, len); |
|
906 fillWithArguments(a, 0, args); |
|
907 return a; |
|
908 } |
|
909 private static void fillWithArguments(Object[] a, int pos, Object... args) { |
|
910 System.arraycopy(args, 0, a, pos, args.length); |
|
911 } |
|
912 // using Integer pos instead of int pos to avoid bootstrapping problems |
|
913 private static Object[] fillArray(Integer pos, Object[] a, Object a0) |
|
914 { fillWithArguments(a, pos, a0); return a; } |
|
915 private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1) |
|
916 { fillWithArguments(a, pos, a0, a1); return a; } |
|
917 private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2) |
|
918 { fillWithArguments(a, pos, a0, a1, a2); return a; } |
|
919 private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3) |
|
920 { fillWithArguments(a, pos, a0, a1, a2, a3); return a; } |
|
921 private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3, |
|
922 Object a4) |
|
923 { fillWithArguments(a, pos, a0, a1, a2, a3, a4); return a; } |
|
924 private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3, |
|
925 Object a4, Object a5) |
|
926 { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5); return a; } |
|
927 private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3, |
|
928 Object a4, Object a5, Object a6) |
|
929 { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6); return a; } |
|
930 private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3, |
|
931 Object a4, Object a5, Object a6, Object a7) |
|
932 { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7); return a; } |
|
933 private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3, |
|
934 Object a4, Object a5, Object a6, Object a7, |
|
935 Object a8) |
|
936 { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7, a8); return a; } |
|
937 private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3, |
|
938 Object a4, Object a5, Object a6, Object a7, |
|
939 Object a8, Object a9) |
|
940 { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); return a; } |
|
941 private static MethodHandle[] makeFillArrays() { |
|
942 ArrayList<MethodHandle> mhs = new ArrayList<>(); |
|
943 mhs.add(null); // there is no empty fill; at least a0 is required |
|
944 for (;;) { |
|
945 MethodHandle mh = findCollector("fillArray", mhs.size(), Object[].class, Integer.class, Object[].class); |
|
946 if (mh == null) break; |
|
947 mhs.add(mh); |
|
948 } |
|
949 assert(mhs.size() == 11); // current number of methods |
|
950 return mhs.toArray(new MethodHandle[0]); |
|
951 } |
|
952 private static final MethodHandle[] FILL_ARRAYS = makeFillArrays(); |
|
953 |
|
954 private static Object[] copyAsReferenceArray(Class<? extends Object[]> arrayType, Object... a) { |
|
955 return Arrays.copyOf(a, a.length, arrayType); |
|
956 } |
|
957 private static Object copyAsPrimitiveArray(Wrapper w, Object... boxes) { |
|
958 Object a = w.makeArray(boxes.length); |
|
959 w.copyArrayUnboxing(boxes, 0, a, 0, boxes.length); |
|
960 return a; |
|
961 } |
|
962 |
|
963 /** Return a method handle that takes the indicated number of Object |
|
964 * arguments and returns an Object array of them, as if for varargs. |
|
965 */ |
|
966 public static MethodHandle varargsArray(int nargs) { |
|
967 MethodHandle mh = ARRAYS[nargs]; |
|
968 if (mh != null) return mh; |
|
969 mh = findCollector("array", nargs, Object[].class); |
|
970 if (mh != null) return ARRAYS[nargs] = mh; |
|
971 mh = buildVarargsArray(FILL_NEW_ARRAY, ARRAY_IDENTITY, nargs); |
|
972 assert(assertCorrectArity(mh, nargs)); |
|
973 return ARRAYS[nargs] = mh; |
|
974 } |
|
975 |
|
976 private static boolean assertCorrectArity(MethodHandle mh, int arity) { |
|
977 assert(mh.type().parameterCount() == arity) : "arity != "+arity+": "+mh; |
|
978 return true; |
|
979 } |
|
980 |
|
981 private static MethodHandle buildVarargsArray(MethodHandle newArray, MethodHandle finisher, int nargs) { |
|
982 // Build up the result mh as a sequence of fills like this: |
|
983 // finisher(fill(fill(newArrayWA(23,x1..x10),10,x11..x20),20,x21..x23)) |
|
984 // The various fill(_,10*I,___*[J]) are reusable. |
|
985 int leftLen = Math.min(nargs, LEFT_ARGS); // absorb some arguments immediately |
|
986 int rightLen = nargs - leftLen; |
|
987 MethodHandle leftCollector = newArray.bindTo(nargs); |
|
988 leftCollector = leftCollector.asCollector(Object[].class, leftLen); |
|
989 MethodHandle mh = finisher; |
|
990 if (rightLen > 0) { |
|
991 MethodHandle rightFiller = fillToRight(LEFT_ARGS + rightLen); |
|
992 if (mh == ARRAY_IDENTITY) |
|
993 mh = rightFiller; |
|
994 else |
|
995 mh = MethodHandles.collectArguments(mh, 0, rightFiller); |
|
996 } |
|
997 if (mh == ARRAY_IDENTITY) |
|
998 mh = leftCollector; |
|
999 else |
|
1000 mh = MethodHandles.collectArguments(mh, 0, leftCollector); |
|
1001 return mh; |
|
1002 } |
|
1003 |
|
1004 private static final int LEFT_ARGS = (FILL_ARRAYS.length - 1); |
|
1005 private static final MethodHandle[] FILL_ARRAY_TO_RIGHT = new MethodHandle[MAX_ARITY+1]; |
|
1006 /** fill_array_to_right(N).invoke(a, argL..arg[N-1]) |
|
1007 * fills a[L]..a[N-1] with corresponding arguments, |
|
1008 * and then returns a. The value L is a global constant (LEFT_ARGS). |
|
1009 */ |
|
1010 private static MethodHandle fillToRight(int nargs) { |
|
1011 MethodHandle filler = FILL_ARRAY_TO_RIGHT[nargs]; |
|
1012 if (filler != null) return filler; |
|
1013 filler = buildFiller(nargs); |
|
1014 assert(assertCorrectArity(filler, nargs - LEFT_ARGS + 1)); |
|
1015 return FILL_ARRAY_TO_RIGHT[nargs] = filler; |
|
1016 } |
|
1017 private static MethodHandle buildFiller(int nargs) { |
|
1018 if (nargs <= LEFT_ARGS) |
|
1019 return ARRAY_IDENTITY; // no args to fill; return the array unchanged |
|
1020 // we need room for both mh and a in mh.invoke(a, arg*[nargs]) |
|
1021 final int CHUNK = LEFT_ARGS; |
|
1022 int rightLen = nargs % CHUNK; |
|
1023 int midLen = nargs - rightLen; |
|
1024 if (rightLen == 0) { |
|
1025 midLen = nargs - (rightLen = CHUNK); |
|
1026 if (FILL_ARRAY_TO_RIGHT[midLen] == null) { |
|
1027 // build some precursors from left to right |
|
1028 for (int j = LEFT_ARGS % CHUNK; j < midLen; j += CHUNK) |
|
1029 if (j > LEFT_ARGS) fillToRight(j); |
|
1030 } |
|
1031 } |
|
1032 if (midLen < LEFT_ARGS) rightLen = nargs - (midLen = LEFT_ARGS); |
|
1033 assert(rightLen > 0); |
|
1034 MethodHandle midFill = fillToRight(midLen); // recursive fill |
|
1035 MethodHandle rightFill = FILL_ARRAYS[rightLen].bindTo(midLen); // [midLen..nargs-1] |
|
1036 assert(midFill.type().parameterCount() == 1 + midLen - LEFT_ARGS); |
|
1037 assert(rightFill.type().parameterCount() == 1 + rightLen); |
|
1038 |
|
1039 // Combine the two fills: |
|
1040 // right(mid(a, x10..x19), x20..x23) |
|
1041 // The final product will look like this: |
|
1042 // right(mid(newArrayLeft(24, x0..x9), x10..x19), x20..x23) |
|
1043 if (midLen == LEFT_ARGS) |
|
1044 return rightFill; |
|
1045 else |
|
1046 return MethodHandles.collectArguments(rightFill, 0, midFill); |
|
1047 } |
|
1048 |
|
1049 // Type-polymorphic version of varargs maker. |
|
1050 private static final ClassValue<MethodHandle[]> TYPED_COLLECTORS |
|
1051 = new ClassValue<MethodHandle[]>() { |
|
1052 @Override |
|
1053 protected MethodHandle[] computeValue(Class<?> type) { |
|
1054 return new MethodHandle[256]; |
|
1055 } |
|
1056 }; |
|
1057 |
|
1058 static final int MAX_JVM_ARITY = 255; // limit imposed by the JVM |
|
1059 |
|
1060 /** Return a method handle that takes the indicated number of |
|
1061 * typed arguments and returns an array of them. |
|
1062 * The type argument is the array type. |
|
1063 */ |
|
1064 public static MethodHandle varargsArray(Class<?> arrayType, int nargs) { |
|
1065 Class<?> elemType = arrayType.getComponentType(); |
|
1066 if (elemType == null) throw new IllegalArgumentException("not an array: "+arrayType); |
|
1067 // FIXME: Need more special casing and caching here. |
|
1068 if (nargs >= MAX_JVM_ARITY/2 - 1) { |
|
1069 int slots = nargs; |
|
1070 final int MAX_ARRAY_SLOTS = MAX_JVM_ARITY - 1; // 1 for receiver MH |
|
1071 if (arrayType == double[].class || arrayType == long[].class) |
|
1072 slots *= 2; |
|
1073 if (slots > MAX_ARRAY_SLOTS) |
|
1074 throw new IllegalArgumentException("too many arguments: "+arrayType.getSimpleName()+", length "+nargs); |
|
1075 } |
|
1076 if (elemType == Object.class) |
|
1077 return varargsArray(nargs); |
|
1078 // other cases: primitive arrays, subtypes of Object[] |
|
1079 MethodHandle cache[] = TYPED_COLLECTORS.get(elemType); |
|
1080 MethodHandle mh = nargs < cache.length ? cache[nargs] : null; |
|
1081 if (mh != null) return mh; |
|
1082 if (elemType.isPrimitive()) { |
|
1083 MethodHandle builder = FILL_NEW_ARRAY; |
|
1084 MethodHandle producer = buildArrayProducer(arrayType); |
|
1085 mh = buildVarargsArray(builder, producer, nargs); |
|
1086 } else { |
|
1087 @SuppressWarnings("unchecked") |
|
1088 Class<? extends Object[]> objArrayType = (Class<? extends Object[]>) arrayType; |
|
1089 Object[] example = Arrays.copyOf(NO_ARGS_ARRAY, 0, objArrayType); |
|
1090 MethodHandle builder = FILL_NEW_TYPED_ARRAY.bindTo(example); |
|
1091 MethodHandle producer = ARRAY_IDENTITY; |
|
1092 mh = buildVarargsArray(builder, producer, nargs); |
|
1093 } |
|
1094 mh = mh.asType(MethodType.methodType(arrayType, Collections.<Class<?>>nCopies(nargs, elemType))); |
|
1095 assert(assertCorrectArity(mh, nargs)); |
|
1096 if (nargs < cache.length) |
|
1097 cache[nargs] = mh; |
|
1098 return mh; |
|
1099 } |
|
1100 |
|
1101 private static MethodHandle buildArrayProducer(Class<?> arrayType) { |
|
1102 Class<?> elemType = arrayType.getComponentType(); |
|
1103 if (elemType.isPrimitive()) |
|
1104 return LazyStatics.COPY_AS_PRIMITIVE_ARRAY.bindTo(Wrapper.forPrimitiveType(elemType)); |
|
1105 else |
|
1106 return LazyStatics.COPY_AS_REFERENCE_ARRAY.bindTo(arrayType); |
|
1107 } |
|
1108 |
|
1109 // List version of varargs maker. |
|
1110 |
|
1111 private static final List<Object> NO_ARGS_LIST = Arrays.asList(NO_ARGS_ARRAY); |
|
1112 private static List<Object> makeList(Object... args) { return Arrays.asList(args); } |
|
1113 private static List<Object> list() { return NO_ARGS_LIST; } |
|
1114 private static List<Object> list(Object a0) |
|
1115 { return makeList(a0); } |
|
1116 private static List<Object> list(Object a0, Object a1) |
|
1117 { return makeList(a0, a1); } |
|
1118 private static List<Object> list(Object a0, Object a1, Object a2) |
|
1119 { return makeList(a0, a1, a2); } |
|
1120 private static List<Object> list(Object a0, Object a1, Object a2, Object a3) |
|
1121 { return makeList(a0, a1, a2, a3); } |
|
1122 private static List<Object> list(Object a0, Object a1, Object a2, Object a3, |
|
1123 Object a4) |
|
1124 { return makeList(a0, a1, a2, a3, a4); } |
|
1125 private static List<Object> list(Object a0, Object a1, Object a2, Object a3, |
|
1126 Object a4, Object a5) |
|
1127 { return makeList(a0, a1, a2, a3, a4, a5); } |
|
1128 private static List<Object> list(Object a0, Object a1, Object a2, Object a3, |
|
1129 Object a4, Object a5, Object a6) |
|
1130 { return makeList(a0, a1, a2, a3, a4, a5, a6); } |
|
1131 private static List<Object> list(Object a0, Object a1, Object a2, Object a3, |
|
1132 Object a4, Object a5, Object a6, Object a7) |
|
1133 { return makeList(a0, a1, a2, a3, a4, a5, a6, a7); } |
|
1134 private static List<Object> list(Object a0, Object a1, Object a2, Object a3, |
|
1135 Object a4, Object a5, Object a6, Object a7, |
|
1136 Object a8) |
|
1137 { return makeList(a0, a1, a2, a3, a4, a5, a6, a7, a8); } |
|
1138 private static List<Object> list(Object a0, Object a1, Object a2, Object a3, |
|
1139 Object a4, Object a5, Object a6, Object a7, |
|
1140 Object a8, Object a9) |
|
1141 { return makeList(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } |
|
1142 private static MethodHandle[] makeLists() { |
|
1143 ArrayList<MethodHandle> mhs = new ArrayList<>(); |
|
1144 for (;;) { |
|
1145 MethodHandle mh = findCollector("list", mhs.size(), List.class); |
|
1146 if (mh == null) break; |
|
1147 mhs.add(mh); |
|
1148 } |
|
1149 assert(mhs.size() == 11); // current number of methods |
|
1150 return mhs.toArray(new MethodHandle[MAX_ARITY+1]); |
|
1151 } |
|
1152 private static final MethodHandle[] LISTS = makeLists(); |
|
1153 |
|
1154 /** Return a method handle that takes the indicated number of Object |
|
1155 * arguments and returns a List. |
|
1156 */ |
|
1157 public static MethodHandle varargsList(int nargs) { |
|
1158 MethodHandle mh = LISTS[nargs]; |
|
1159 if (mh != null) return mh; |
|
1160 mh = findCollector("list", nargs, List.class); |
|
1161 if (mh != null) return LISTS[nargs] = mh; |
|
1162 return LISTS[nargs] = buildVarargsList(nargs); |
|
1163 } |
|
1164 private static MethodHandle buildVarargsList(int nargs) { |
|
1165 return MethodHandles.filterReturnValue(varargsArray(nargs), LazyStatics.MAKE_LIST); |
|
1166 } |
|
1167 |
|
1168 // handy shared exception makers (they simplify the common case code) |
764 // handy shared exception makers (they simplify the common case code) |
1169 private static InternalError newInternalError(String message, Throwable cause) { |
765 private static InternalError newInternalError(String message, Throwable cause) { |
1170 return new InternalError(message, cause); |
766 return new InternalError(message, cause); |
1171 } |
767 } |
1172 private static InternalError newInternalError(Throwable cause) { |
768 private static InternalError newInternalError(Throwable cause) { |