466 */ |
451 */ |
467 static <T,U> T castReference(Class<? extends T> t, U x) { |
452 static <T,U> T castReference(Class<? extends T> t, U x) { |
468 return t.cast(x); |
453 return t.cast(x); |
469 } |
454 } |
470 |
455 |
471 private static final MethodHandle IDENTITY, CAST_REFERENCE, ALWAYS_NULL, ALWAYS_ZERO, ZERO_OBJECT, IGNORE, EMPTY, NEW_ARRAY; |
456 private static final MethodHandle IDENTITY, CAST_REFERENCE, ZERO_OBJECT, IGNORE, EMPTY, |
|
457 ARRAY_IDENTITY, FILL_NEW_TYPED_ARRAY, FILL_NEW_ARRAY; |
472 static { |
458 static { |
473 try { |
459 try { |
474 MethodType idType = MethodType.genericMethodType(1); |
460 MethodType idType = MethodType.genericMethodType(1); |
475 MethodType castType = idType.insertParameterTypes(0, Class.class); |
461 MethodType castType = idType.insertParameterTypes(0, Class.class); |
476 MethodType alwaysZeroType = idType.changeReturnType(int.class); |
|
477 MethodType ignoreType = idType.changeReturnType(void.class); |
462 MethodType ignoreType = idType.changeReturnType(void.class); |
478 MethodType zeroObjectType = MethodType.genericMethodType(0); |
463 MethodType zeroObjectType = MethodType.genericMethodType(0); |
479 IDENTITY = IMPL_LOOKUP.findStatic(THIS_CLASS, "identity", idType); |
464 IDENTITY = IMPL_LOOKUP.findStatic(THIS_CLASS, "identity", idType); |
480 //CAST_REFERENCE = IMPL_LOOKUP.findVirtual(Class.class, "cast", idType); |
465 //CAST_REFERENCE = IMPL_LOOKUP.findVirtual(Class.class, "cast", idType); |
481 CAST_REFERENCE = IMPL_LOOKUP.findStatic(THIS_CLASS, "castReference", castType); |
466 CAST_REFERENCE = IMPL_LOOKUP.findStatic(THIS_CLASS, "castReference", castType); |
482 ALWAYS_NULL = IMPL_LOOKUP.findStatic(THIS_CLASS, "alwaysNull", idType); |
|
483 ALWAYS_ZERO = IMPL_LOOKUP.findStatic(THIS_CLASS, "alwaysZero", alwaysZeroType); |
|
484 ZERO_OBJECT = IMPL_LOOKUP.findStatic(THIS_CLASS, "zeroObject", zeroObjectType); |
467 ZERO_OBJECT = IMPL_LOOKUP.findStatic(THIS_CLASS, "zeroObject", zeroObjectType); |
485 IGNORE = IMPL_LOOKUP.findStatic(THIS_CLASS, "ignore", ignoreType); |
468 IGNORE = IMPL_LOOKUP.findStatic(THIS_CLASS, "ignore", ignoreType); |
486 EMPTY = IMPL_LOOKUP.findStatic(THIS_CLASS, "empty", ignoreType.dropParameterTypes(0, 1)); |
469 EMPTY = IMPL_LOOKUP.findStatic(THIS_CLASS, "empty", ignoreType.dropParameterTypes(0, 1)); |
487 NEW_ARRAY = IMPL_LOOKUP.findStatic(THIS_CLASS, "newArray", MethodType.methodType(Object[].class, int.class)); |
470 ARRAY_IDENTITY = IMPL_LOOKUP.findStatic(THIS_CLASS, "identity", MethodType.methodType(Object[].class, Object[].class)); |
|
471 FILL_NEW_ARRAY = IMPL_LOOKUP |
|
472 .findStatic(THIS_CLASS, "fillNewArray", |
|
473 MethodType.methodType(Object[].class, Integer.class, Object[].class)); |
|
474 FILL_NEW_TYPED_ARRAY = IMPL_LOOKUP |
|
475 .findStatic(THIS_CLASS, "fillNewTypedArray", |
|
476 MethodType.methodType(Object[].class, Object[].class, Integer.class, Object[].class)); |
488 } catch (NoSuchMethodException | IllegalAccessException ex) { |
477 } catch (NoSuchMethodException | IllegalAccessException ex) { |
489 throw new InternalError("uncaught exception", ex); |
478 throw new InternalError("uncaught exception", ex); |
490 } |
479 } |
491 } |
480 } |
492 |
481 |
493 // Varargs methods need to be in a separately initialized class, to bootstrapping problems. |
482 // Varargs methods need to be in a separately initialized class, to avoid bootstrapping problems. |
494 static class LazyStatics { |
483 static class LazyStatics { |
495 private static final MethodHandle COPY_AS_REFERENCE_ARRAY, COPY_AS_PRIMITIVE_ARRAY, MAKE_LIST; |
484 private static final MethodHandle COPY_AS_REFERENCE_ARRAY, COPY_AS_PRIMITIVE_ARRAY, MAKE_LIST; |
496 static { |
485 static { |
497 try { |
486 try { |
498 //MAKE_ARRAY = IMPL_LOOKUP.findStatic(THIS_CLASS, "makeArray", MethodType.methodType(Object[].class, Object[].class)); |
487 //MAKE_ARRAY = IMPL_LOOKUP.findStatic(THIS_CLASS, "makeArray", MethodType.methodType(Object[].class, Object[].class)); |
503 throw new InternalError("uncaught exception", ex); |
492 throw new InternalError("uncaught exception", ex); |
504 } |
493 } |
505 } |
494 } |
506 } |
495 } |
507 |
496 |
|
497 static MethodHandle collectArguments(MethodHandle mh, int pos, MethodHandle collector) { |
|
498 // FIXME: API needs public MHs.collectArguments. |
|
499 // Should be: |
|
500 // return MethodHandles.collectArguments(mh, 0, collector); |
|
501 // The rest of this code is a workaround for not having that API. |
|
502 if (COLLECT_ARGUMENTS != null) { |
|
503 try { |
|
504 return (MethodHandle) |
|
505 COLLECT_ARGUMENTS.invokeExact(mh, pos, collector); |
|
506 } catch (Throwable ex) { |
|
507 if (ex instanceof RuntimeException) |
|
508 throw (RuntimeException) ex; |
|
509 if (ex instanceof Error) |
|
510 throw (Error) ex; |
|
511 throw new Error(ex.getMessage(), ex); |
|
512 } |
|
513 } |
|
514 // Emulate MHs.collectArguments using fold + drop. |
|
515 // This is slightly inefficient. |
|
516 // More seriously, it can put a MH over the 255-argument limit. |
|
517 mh = MethodHandles.dropArguments(mh, 1, collector.type().parameterList()); |
|
518 mh = MethodHandles.foldArguments(mh, collector); |
|
519 return mh; |
|
520 } |
|
521 private static final MethodHandle COLLECT_ARGUMENTS; |
|
522 static { |
|
523 MethodHandle mh = null; |
|
524 try { |
|
525 java.lang.reflect.Method m = MethodHandles.class |
|
526 .getDeclaredMethod("collectArguments", |
|
527 MethodHandle.class, int.class, MethodHandle.class); |
|
528 m.setAccessible(true); |
|
529 mh = IMPL_LOOKUP.unreflect(m); |
|
530 |
|
531 } catch (ReflectiveOperationException | SecurityException ex) { |
|
532 throw new InternalError(ex); |
|
533 } |
|
534 COLLECT_ARGUMENTS = mh; |
|
535 } |
|
536 |
508 private static final EnumMap<Wrapper, MethodHandle>[] WRAPPER_CASTS |
537 private static final EnumMap<Wrapper, MethodHandle>[] WRAPPER_CASTS |
509 = newWrapperCaches(2); |
538 = newWrapperCaches(1); |
510 |
539 |
511 /** Return a method that casts its sole argument (an Object) to the given type |
540 /** Return a method that casts its sole argument (an Object) to the given type |
512 * and returns it as the given type (if exact is true), or as plain Object (if erase is true). |
541 * and returns it as the given type. |
513 */ |
542 */ |
514 public static MethodHandle cast(Class<?> type) { |
543 public static MethodHandle cast(Class<?> type) { |
515 boolean exact = false; |
|
516 if (type.isPrimitive()) throw new IllegalArgumentException("cannot cast primitive type "+type); |
544 if (type.isPrimitive()) throw new IllegalArgumentException("cannot cast primitive type "+type); |
517 MethodHandle mh = null; |
545 MethodHandle mh; |
518 Wrapper wrap = null; |
546 Wrapper wrap = null; |
519 EnumMap<Wrapper, MethodHandle> cache = null; |
547 EnumMap<Wrapper, MethodHandle> cache = null; |
520 if (Wrapper.isWrapperType(type)) { |
548 if (Wrapper.isWrapperType(type)) { |
521 wrap = Wrapper.forWrapperType(type); |
549 wrap = Wrapper.forWrapperType(type); |
522 cache = WRAPPER_CASTS[exact?1:0]; |
550 cache = WRAPPER_CASTS[0]; |
523 mh = cache.get(wrap); |
551 mh = cache.get(wrap); |
524 if (mh != null) return mh; |
552 if (mh != null) return mh; |
525 } |
553 } |
526 if (VerifyType.isNullReferenceConversion(Object.class, type)) |
554 mh = MethodHandles.insertArguments(CAST_REFERENCE, 0, type); |
527 mh = IDENTITY; |
|
528 else if (VerifyType.isNullType(type)) |
|
529 mh = ALWAYS_NULL; |
|
530 else |
|
531 mh = MethodHandles.insertArguments(CAST_REFERENCE, 0, type); |
|
532 if (exact) { |
|
533 MethodType xmt = MethodType.methodType(type, Object.class); |
|
534 mh = MethodHandles.explicitCastArguments(mh, xmt); |
|
535 } |
|
536 if (cache != null) |
555 if (cache != null) |
537 cache.put(wrap, mh); |
556 cache.put(wrap, mh); |
538 return mh; |
557 return mh; |
539 } |
558 } |
540 |
559 |
918 assert(mhs.size() == 11); // current number of methods |
937 assert(mhs.size() == 11); // current number of methods |
919 return mhs.toArray(new MethodHandle[MAX_ARITY+1]); |
938 return mhs.toArray(new MethodHandle[MAX_ARITY+1]); |
920 } |
939 } |
921 private static final MethodHandle[] ARRAYS = makeArrays(); |
940 private static final MethodHandle[] ARRAYS = makeArrays(); |
922 |
941 |
923 // mh-fill versions of the above: |
942 // filling versions of the above: |
924 private static Object[] newArray(int len) { return new Object[len]; } |
943 // using Integer len instead of int len and no varargs to avoid bootstrapping problems |
|
944 private static Object[] fillNewArray(Integer len, Object[] /*not ...*/ args) { |
|
945 Object[] a = new Object[len]; |
|
946 fillWithArguments(a, 0, args); |
|
947 return a; |
|
948 } |
|
949 private static Object[] fillNewTypedArray(Object[] example, Integer len, Object[] /*not ...*/ args) { |
|
950 Object[] a = Arrays.copyOf(example, len); |
|
951 fillWithArguments(a, 0, args); |
|
952 return a; |
|
953 } |
925 private static void fillWithArguments(Object[] a, int pos, Object... args) { |
954 private static void fillWithArguments(Object[] a, int pos, Object... args) { |
926 System.arraycopy(args, 0, a, pos, args.length); |
955 System.arraycopy(args, 0, a, pos, args.length); |
927 } |
956 } |
928 // using Integer pos instead of int pos to avoid bootstrapping problems |
957 // using Integer pos instead of int pos to avoid bootstrapping problems |
929 private static Object[] fillArray(Object[] a, Integer pos, Object a0) |
958 private static Object[] fillArray(Integer pos, Object[] a, Object a0) |
930 { fillWithArguments(a, pos, a0); return a; } |
959 { fillWithArguments(a, pos, a0); return a; } |
931 private static Object[] fillArray(Object[] a, Integer pos, Object a0, Object a1) |
960 private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1) |
932 { fillWithArguments(a, pos, a0, a1); return a; } |
961 { fillWithArguments(a, pos, a0, a1); return a; } |
933 private static Object[] fillArray(Object[] a, Integer pos, Object a0, Object a1, Object a2) |
962 private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2) |
934 { fillWithArguments(a, pos, a0, a1, a2); return a; } |
963 { fillWithArguments(a, pos, a0, a1, a2); return a; } |
935 private static Object[] fillArray(Object[] a, Integer pos, Object a0, Object a1, Object a2, Object a3) |
964 private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3) |
936 { fillWithArguments(a, pos, a0, a1, a2, a3); return a; } |
965 { fillWithArguments(a, pos, a0, a1, a2, a3); return a; } |
937 private static Object[] fillArray(Object[] a, Integer pos, Object a0, Object a1, Object a2, Object a3, |
966 private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3, |
938 Object a4) |
967 Object a4) |
939 { fillWithArguments(a, pos, a0, a1, a2, a3, a4); return a; } |
968 { fillWithArguments(a, pos, a0, a1, a2, a3, a4); return a; } |
940 private static Object[] fillArray(Object[] a, Integer pos, Object a0, Object a1, Object a2, Object a3, |
969 private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3, |
941 Object a4, Object a5) |
970 Object a4, Object a5) |
942 { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5); return a; } |
971 { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5); return a; } |
943 private static Object[] fillArray(Object[] a, Integer pos, Object a0, Object a1, Object a2, Object a3, |
972 private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3, |
944 Object a4, Object a5, Object a6) |
973 Object a4, Object a5, Object a6) |
945 { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6); return a; } |
974 { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6); return a; } |
946 private static Object[] fillArray(Object[] a, Integer pos, Object a0, Object a1, Object a2, Object a3, |
975 private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3, |
947 Object a4, Object a5, Object a6, Object a7) |
976 Object a4, Object a5, Object a6, Object a7) |
948 { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7); return a; } |
977 { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7); return a; } |
949 private static Object[] fillArray(Object[] a, Integer pos, Object a0, Object a1, Object a2, Object a3, |
978 private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3, |
950 Object a4, Object a5, Object a6, Object a7, |
979 Object a4, Object a5, Object a6, Object a7, |
951 Object a8) |
980 Object a8) |
952 { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7, a8); return a; } |
981 { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7, a8); return a; } |
953 private static Object[] fillArray(Object[] a, Integer pos, Object a0, Object a1, Object a2, Object a3, |
982 private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3, |
954 Object a4, Object a5, Object a6, Object a7, |
983 Object a4, Object a5, Object a6, Object a7, |
955 Object a8, Object a9) |
984 Object a8, Object a9) |
956 { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); return a; } |
985 { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); return a; } |
957 private static MethodHandle[] makeFillArrays() { |
986 private static MethodHandle[] makeFillArrays() { |
958 ArrayList<MethodHandle> mhs = new ArrayList<>(); |
987 ArrayList<MethodHandle> mhs = new ArrayList<>(); |
959 mhs.add(null); // there is no empty fill; at least a0 is required |
988 mhs.add(null); // there is no empty fill; at least a0 is required |
960 for (;;) { |
989 for (;;) { |
961 MethodHandle mh = findCollector("fillArray", mhs.size(), Object[].class, Object[].class, Integer.class); |
990 MethodHandle mh = findCollector("fillArray", mhs.size(), Object[].class, Integer.class, Object[].class); |
962 if (mh == null) break; |
991 if (mh == null) break; |
963 mhs.add(mh); |
992 mhs.add(mh); |
964 } |
993 } |
965 assert(mhs.size() == 11); // current number of methods |
994 assert(mhs.size() == 11); // current number of methods |
966 return mhs.toArray(new MethodHandle[0]); |
995 return mhs.toArray(new MethodHandle[0]); |
982 public static MethodHandle varargsArray(int nargs) { |
1011 public static MethodHandle varargsArray(int nargs) { |
983 MethodHandle mh = ARRAYS[nargs]; |
1012 MethodHandle mh = ARRAYS[nargs]; |
984 if (mh != null) return mh; |
1013 if (mh != null) return mh; |
985 mh = findCollector("array", nargs, Object[].class); |
1014 mh = findCollector("array", nargs, Object[].class); |
986 if (mh != null) return ARRAYS[nargs] = mh; |
1015 if (mh != null) return ARRAYS[nargs] = mh; |
987 MethodHandle producer = filler(0); // identity function produces result |
1016 mh = buildVarargsArray(FILL_NEW_ARRAY, ARRAY_IDENTITY, nargs); |
988 return ARRAYS[nargs] = buildVarargsArray(producer, nargs); |
1017 assert(assertCorrectArity(mh, nargs)); |
989 } |
1018 return ARRAYS[nargs] = mh; |
990 |
1019 } |
991 private static MethodHandle buildVarargsArray(MethodHandle producer, int nargs) { |
1020 |
|
1021 private static boolean assertCorrectArity(MethodHandle mh, int arity) { |
|
1022 assert(mh.type().parameterCount() == arity) : "arity != "+arity+": "+mh; |
|
1023 return true; |
|
1024 } |
|
1025 |
|
1026 private static MethodHandle buildVarargsArray(MethodHandle newArray, MethodHandle finisher, int nargs) { |
992 // Build up the result mh as a sequence of fills like this: |
1027 // Build up the result mh as a sequence of fills like this: |
993 // producer(fill(fill(fill(newArray(23),0,x1..x10),10,x11..x20),20,x21..x23)) |
1028 // finisher(fill(fill(newArrayWA(23,x1..x10),10,x11..x20),20,x21..x23)) |
994 // The various fill(_,10*I,___*[J]) are reusable. |
1029 // The various fill(_,10*I,___*[J]) are reusable. |
995 MethodHandle filler = filler(nargs); |
1030 int leftLen = Math.min(nargs, LEFT_ARGS); // absorb some arguments immediately |
996 MethodHandle mh = producer; |
1031 int rightLen = nargs - leftLen; |
997 mh = MethodHandles.dropArguments(mh, 1, filler.type().parameterList()); |
1032 MethodHandle leftCollector = newArray.bindTo(nargs); |
998 mh = MethodHandles.foldArguments(mh, filler); |
1033 leftCollector = leftCollector.asCollector(Object[].class, leftLen); |
999 mh = MethodHandles.foldArguments(mh, buildNewArray(nargs)); |
1034 MethodHandle mh = finisher; |
|
1035 if (rightLen > 0) { |
|
1036 MethodHandle rightFiller = fillToRight(LEFT_ARGS + rightLen); |
|
1037 if (mh == ARRAY_IDENTITY) |
|
1038 mh = rightFiller; |
|
1039 else |
|
1040 mh = collectArguments(mh, 0, rightFiller); |
|
1041 } |
|
1042 if (mh == ARRAY_IDENTITY) |
|
1043 mh = leftCollector; |
|
1044 else |
|
1045 mh = collectArguments(mh, 0, leftCollector); |
1000 return mh; |
1046 return mh; |
1001 } |
1047 } |
1002 |
1048 |
1003 private static MethodHandle buildNewArray(int nargs) { |
1049 private static final int LEFT_ARGS = (FILL_ARRAYS.length - 1); |
1004 return MethodHandles.insertArguments(NEW_ARRAY, 0, nargs); |
1050 private static final MethodHandle[] FILL_ARRAY_TO_RIGHT = new MethodHandle[MAX_ARITY+1]; |
1005 } |
1051 /** fill_array_to_right(N).invoke(a, argL..arg[N-1]) |
1006 |
1052 * fills a[L]..a[N-1] with corresponding arguments, |
1007 private static final MethodHandle[] FILLERS = new MethodHandle[MAX_ARITY+1]; |
1053 * and then returns a. The value L is a global constant (LEFT_ARGS). |
1008 // filler(N).invoke(a, arg0..arg[N-1]) fills a[0]..a[N-1] |
1054 */ |
1009 private static MethodHandle filler(int nargs) { |
1055 private static MethodHandle fillToRight(int nargs) { |
1010 MethodHandle filler = FILLERS[nargs]; |
1056 MethodHandle filler = FILL_ARRAY_TO_RIGHT[nargs]; |
1011 if (filler != null) return filler; |
1057 if (filler != null) return filler; |
1012 return FILLERS[nargs] = buildFiller(nargs); |
1058 filler = buildFiller(nargs); |
|
1059 assert(assertCorrectArity(filler, nargs - LEFT_ARGS + 1)); |
|
1060 return FILL_ARRAY_TO_RIGHT[nargs] = filler; |
1013 } |
1061 } |
1014 private static MethodHandle buildFiller(int nargs) { |
1062 private static MethodHandle buildFiller(int nargs) { |
1015 if (nargs == 0) |
1063 if (nargs <= LEFT_ARGS) |
1016 return MethodHandles.identity(Object[].class); |
1064 return ARRAY_IDENTITY; // no args to fill; return the array unchanged |
1017 final int CHUNK = (FILL_ARRAYS.length - 1); |
1065 // we need room for both mh and a in mh.invoke(a, arg*[nargs]) |
|
1066 final int CHUNK = LEFT_ARGS; |
1018 int rightLen = nargs % CHUNK; |
1067 int rightLen = nargs % CHUNK; |
1019 int leftLen = nargs - rightLen; |
1068 int midLen = nargs - rightLen; |
1020 if (rightLen == 0) { |
1069 if (rightLen == 0) { |
1021 leftLen = nargs - (rightLen = CHUNK); |
1070 midLen = nargs - (rightLen = CHUNK); |
1022 if (FILLERS[leftLen] == null) { |
1071 if (FILL_ARRAY_TO_RIGHT[midLen] == null) { |
1023 // build some precursors from left to right |
1072 // build some precursors from left to right |
1024 for (int j = 0; j < leftLen; j += CHUNK) filler(j); |
1073 for (int j = LEFT_ARGS % CHUNK; j < midLen; j += CHUNK) |
|
1074 if (j > LEFT_ARGS) fillToRight(j); |
1025 } |
1075 } |
1026 } |
1076 } |
1027 MethodHandle leftFill = filler(leftLen); // recursive fill |
1077 if (midLen < LEFT_ARGS) rightLen = nargs - (midLen = LEFT_ARGS); |
1028 MethodHandle rightFill = FILL_ARRAYS[rightLen]; |
1078 assert(rightLen > 0); |
1029 rightFill = MethodHandles.insertArguments(rightFill, 1, leftLen); // [leftLen..nargs-1] |
1079 MethodHandle midFill = fillToRight(midLen); // recursive fill |
1030 |
1080 MethodHandle rightFill = FILL_ARRAYS[rightLen].bindTo(midLen); // [midLen..nargs-1] |
1031 // Combine the two fills: right(left(newArray(nargs), x1..x20), x21..x23) |
1081 assert(midFill.type().parameterCount() == 1 + midLen - LEFT_ARGS); |
1032 MethodHandle mh = filler(0); // identity function produces result |
1082 assert(rightFill.type().parameterCount() == 1 + rightLen); |
1033 mh = MethodHandles.dropArguments(mh, 1, rightFill.type().parameterList()); |
1083 |
1034 mh = MethodHandles.foldArguments(mh, rightFill); |
1084 // Combine the two fills: |
1035 if (leftLen > 0) { |
1085 // right(mid(a, x10..x19), x20..x23) |
1036 mh = MethodHandles.dropArguments(mh, 1, leftFill.type().parameterList()); |
1086 // The final product will look like this: |
1037 mh = MethodHandles.foldArguments(mh, leftFill); |
1087 // right(mid(newArrayLeft(24, x0..x9), x10..x19), x20..x23) |
1038 } |
1088 if (midLen == LEFT_ARGS) |
1039 return mh; |
1089 return rightFill; |
|
1090 else |
|
1091 return collectArguments(rightFill, 0, midFill); |
1040 } |
1092 } |
1041 |
1093 |
1042 // Type-polymorphic version of varargs maker. |
1094 // Type-polymorphic version of varargs maker. |
1043 private static final ClassValue<MethodHandle[]> TYPED_COLLECTORS |
1095 private static final ClassValue<MethodHandle[]> TYPED_COLLECTORS |
1044 = new ClassValue<MethodHandle[]>() { |
1096 = new ClassValue<MethodHandle[]>() { |
|
1097 @Override |
1045 protected MethodHandle[] computeValue(Class<?> type) { |
1098 protected MethodHandle[] computeValue(Class<?> type) { |
1046 return new MethodHandle[256]; |
1099 return new MethodHandle[256]; |
1047 } |
1100 } |
1048 }; |
1101 }; |
|
1102 |
|
1103 static final int MAX_JVM_ARITY = 255; // limit imposed by the JVM |
1049 |
1104 |
1050 /** Return a method handle that takes the indicated number of |
1105 /** Return a method handle that takes the indicated number of |
1051 * typed arguments and returns an array of them. |
1106 * typed arguments and returns an array of them. |
1052 * The type argument is the array type. |
1107 * The type argument is the array type. |
1053 */ |
1108 */ |
1054 public static MethodHandle varargsArray(Class<?> arrayType, int nargs) { |
1109 public static MethodHandle varargsArray(Class<?> arrayType, int nargs) { |
1055 Class<?> elemType = arrayType.getComponentType(); |
1110 Class<?> elemType = arrayType.getComponentType(); |
1056 if (elemType == null) throw new IllegalArgumentException("not an array: "+arrayType); |
1111 if (elemType == null) throw new IllegalArgumentException("not an array: "+arrayType); |
1057 // FIXME: Need more special casing and caching here. |
1112 // FIXME: Need more special casing and caching here. |
|
1113 if (nargs >= MAX_JVM_ARITY/2 - 1) { |
|
1114 int slots = nargs; |
|
1115 final int MAX_ARRAY_SLOTS = MAX_JVM_ARITY - 1; // 1 for receiver MH |
|
1116 if (arrayType == double[].class || arrayType == long[].class) |
|
1117 slots *= 2; |
|
1118 if (slots > MAX_ARRAY_SLOTS) |
|
1119 throw new IllegalArgumentException("too many arguments: "+arrayType.getSimpleName()+", length "+nargs); |
|
1120 } |
1058 if (elemType == Object.class) |
1121 if (elemType == Object.class) |
1059 return varargsArray(nargs); |
1122 return varargsArray(nargs); |
1060 // other cases: primitive arrays, subtypes of Object[] |
1123 // other cases: primitive arrays, subtypes of Object[] |
1061 MethodHandle cache[] = TYPED_COLLECTORS.get(elemType); |
1124 MethodHandle cache[] = TYPED_COLLECTORS.get(elemType); |
1062 MethodHandle mh = nargs < cache.length ? cache[nargs] : null; |
1125 MethodHandle mh = nargs < cache.length ? cache[nargs] : null; |
1063 if (mh != null) return mh; |
1126 if (mh != null) return mh; |
1064 MethodHandle producer = buildArrayProducer(arrayType); |
1127 if (elemType.isPrimitive()) { |
1065 mh = buildVarargsArray(producer, nargs); |
1128 MethodHandle builder = FILL_NEW_ARRAY; |
|
1129 MethodHandle producer = buildArrayProducer(arrayType); |
|
1130 mh = buildVarargsArray(builder, producer, nargs); |
|
1131 } else { |
|
1132 @SuppressWarnings("unchecked") |
|
1133 Class<? extends Object[]> objArrayType = (Class<? extends Object[]>) arrayType; |
|
1134 Object[] example = Arrays.copyOf(NO_ARGS_ARRAY, 0, objArrayType); |
|
1135 MethodHandle builder = FILL_NEW_TYPED_ARRAY.bindTo(example); |
|
1136 MethodHandle producer = ARRAY_IDENTITY; |
|
1137 mh = buildVarargsArray(builder, producer, nargs); |
|
1138 } |
1066 mh = mh.asType(MethodType.methodType(arrayType, Collections.<Class<?>>nCopies(nargs, elemType))); |
1139 mh = mh.asType(MethodType.methodType(arrayType, Collections.<Class<?>>nCopies(nargs, elemType))); |
1067 cache[nargs] = mh; |
1140 assert(assertCorrectArity(mh, nargs)); |
|
1141 if (nargs < cache.length) |
|
1142 cache[nargs] = mh; |
1068 return mh; |
1143 return mh; |
1069 } |
1144 } |
1070 |
1145 |
1071 private static MethodHandle buildArrayProducer(Class<?> arrayType) { |
1146 private static MethodHandle buildArrayProducer(Class<?> arrayType) { |
1072 Class<?> elemType = arrayType.getComponentType(); |
1147 Class<?> elemType = arrayType.getComponentType(); |