852 * @param arrayType usually {@code Object[]}, the type of the array argument from which to extract the spread arguments
853 * @param arrayLength the number of arguments to spread from an incoming array argument
854 * @return a new method handle which spreads its final array argument,
855 * before calling the original method handle
856 * @throws NullPointerException if {@code arrayType} is a null reference
857 * @throws IllegalArgumentException if {@code arrayType} is not an array type,
858 * or if target does not have at least
859 * {@code arrayLength} parameter types,
860 * or if {@code arrayLength} is negative,
861 * or if the resulting method handle's type would have
862 * <a href="MethodHandle.html#maxarity">too many parameters</a>
863 * @throws WrongMethodTypeException if the implied {@code asType} call fails
864 * @see #asCollector
865 */
866 public MethodHandle asSpreader(Class<?> arrayType, int arrayLength) {
867 asSpreaderChecks(arrayType, arrayLength);
868 int spreadArgPos = type.parameterCount() - arrayLength;
869 return MethodHandleImpl.makeSpreadArguments(this, arrayType, spreadArgPos, arrayLength);
870 }
871
872 private void asSpreaderChecks(Class<?> arrayType, int arrayLength) {
873 spreadArrayChecks(arrayType, arrayLength);
874 int nargs = type().parameterCount();
875 if (nargs < arrayLength || arrayLength < 0)
876 throw newIllegalArgumentException("bad spread array length");
877 if (arrayType != Object[].class && arrayLength != 0) {
878 boolean sawProblem = false;
879 Class<?> arrayElement = arrayType.getComponentType();
880 for (int i = nargs - arrayLength; i < nargs; i++) {
881 if (!MethodType.canConvert(arrayElement, type().parameterType(i))) {
882 sawProblem = true;
883 break;
884 }
885 }
886 if (sawProblem) {
887 ArrayList<Class<?>> ptypes = new ArrayList<>(type().parameterList());
888 for (int i = nargs - arrayLength; i < nargs; i++) {
889 ptypes.set(i, arrayElement);
890 }
891 // elicit an error:
892 this.asType(MethodType.methodType(type().returnType(), ptypes));
893 }
894 }
895 }
896
897 private void spreadArrayChecks(Class<?> arrayType, int arrayLength) {
898 Class<?> arrayElement = arrayType.getComponentType();
899 if (arrayElement == null)
900 throw newIllegalArgumentException("not an array type", arrayType);
901 if ((arrayLength & 0x7F) != arrayLength) {
902 if ((arrayLength & 0xFF) != arrayLength)
903 throw newIllegalArgumentException("array length is not legal", arrayLength);
904 assert(arrayLength >= 128);
905 if (arrayElement == long.class ||
906 arrayElement == double.class)
907 throw newIllegalArgumentException("array length is not legal for long[] or double[]", arrayLength);
908 }
909 }
910
911 /**
912 * Makes an <em>array-collecting</em> method handle, which accepts a given number of trailing
913 * positional arguments and collects them into an array argument.
914 * The new method handle adapts, as its <i>target</i>,
|
852 * @param arrayType usually {@code Object[]}, the type of the array argument from which to extract the spread arguments
853 * @param arrayLength the number of arguments to spread from an incoming array argument
854 * @return a new method handle which spreads its final array argument,
855 * before calling the original method handle
856 * @throws NullPointerException if {@code arrayType} is a null reference
857 * @throws IllegalArgumentException if {@code arrayType} is not an array type,
858 * or if target does not have at least
859 * {@code arrayLength} parameter types,
860 * or if {@code arrayLength} is negative,
861 * or if the resulting method handle's type would have
862 * <a href="MethodHandle.html#maxarity">too many parameters</a>
863 * @throws WrongMethodTypeException if the implied {@code asType} call fails
864 * @see #asCollector
865 */
866 public MethodHandle asSpreader(Class<?> arrayType, int arrayLength) {
867 asSpreaderChecks(arrayType, arrayLength);
868 int spreadArgPos = type.parameterCount() - arrayLength;
869 return MethodHandleImpl.makeSpreadArguments(this, arrayType, spreadArgPos, arrayLength);
870 }
871
872 /**
873 * See if {@code asSpreader} can be validly called with the given arguments.
874 * Return the type of the method handle call after spreading but before conversions.
875 */
876 private MethodType asSpreaderChecks(Class<?> arrayType, int arrayLength) {
877 spreadArrayChecks(arrayType, arrayLength);
878 int nargs = type().parameterCount();
879 if (nargs < arrayLength || arrayLength < 0)
880 throw newIllegalArgumentException("bad spread array length");
881 Class<?> arrayElement = arrayType.getComponentType();
882 MethodType mtype = type();
883 boolean match = true, fail = false;
884 for (int i = nargs - arrayLength; i < nargs; i++) {
885 Class<?> ptype = mtype.parameterType(i);
886 if (ptype != arrayElement) {
887 match = false;
888 if (!MethodType.canConvert(arrayElement, ptype)) {
889 fail = true;
890 break;
891 }
892 }
893 }
894 if (match) return mtype;
895 MethodType needType = mtype.asSpreaderType(arrayType, arrayLength);
896 if (!fail) return needType;
897 // elicit an error:
898 this.asType(needType);
899 throw newInternalError("should not return", null);
900 }
901
902 private void spreadArrayChecks(Class<?> arrayType, int arrayLength) {
903 Class<?> arrayElement = arrayType.getComponentType();
904 if (arrayElement == null)
905 throw newIllegalArgumentException("not an array type", arrayType);
906 if ((arrayLength & 0x7F) != arrayLength) {
907 if ((arrayLength & 0xFF) != arrayLength)
908 throw newIllegalArgumentException("array length is not legal", arrayLength);
909 assert(arrayLength >= 128);
910 if (arrayElement == long.class ||
911 arrayElement == double.class)
912 throw newIllegalArgumentException("array length is not legal for long[] or double[]", arrayLength);
913 }
914 }
915
916 /**
917 * Makes an <em>array-collecting</em> method handle, which accepts a given number of trailing
918 * positional arguments and collects them into an array argument.
919 * The new method handle adapts, as its <i>target</i>,
|