--- old/src/java.base/share/classes/java/lang/invoke/MethodHandles.java 2016-02-29 14:38:03.000000000 +0100 +++ new/src/java.base/share/classes/java/lang/invoke/MethodHandles.java 2016-02-29 14:38:03.000000000 +0100 @@ -3268,12 +3268,17 @@ *
  • This list of types is called the "common prefix". * *

    - * Step 1B: Determine loop parameters.

      - *
    1. Examine init function parameter lists. - *
    2. Omitted init functions are deemed to have {@code null} parameter lists. - *
    3. All init function parameter lists must be effectively identical. - *
    4. The longest parameter list (which is necessarily unique) is called the "common suffix". + * Step 1B: Determine loop parameters.
        + *
      • If at least one init function is given,
          + *
        1. Examine init function parameter lists. + *
        2. Omitted init functions are deemed to have {@code null} parameter lists. + *
        3. All init function parameter lists must be effectively identical. + *
        4. The longest parameter list (which is necessarily unique) is called the "common suffix". *
        + *
      • If no init function is given,
          + *
        1. Examine the suffixes of the step, pred, and fini parameter lists, after removing the "common prefix". + *
        2. The longest of these suffixes is taken as the "common suffix". + *
      *

      * Step 1C: Determine loop return type.

        *
      1. Examine fini function return types, disregarding omitted fini functions. @@ -3286,9 +3291,6 @@ *
      2. Every non-omitted pred function must have a {@code boolean} return type. *
      *

      - * (Implementation Note: Steps 1A, 1B, 1C, 1D are logically independent of each other, and may be performed in any - * order.) - *

      * Step 2: Determine parameter lists.

        *
      1. The parameter list for the resulting loop handle will be the "common suffix". *
      2. The parameter list for init functions will be adjusted to the "common suffix". (Note that their parameter @@ -3375,10 +3377,10 @@ *
        {@code
              * // iterative implementation of the factorial function as a loop handle
              * static int one(int k) { return 1; }
        -     * int inc(int i, int acc, int k) { return i + 1; }
        -     * int mult(int i, int acc, int k) { return i * acc; }
        -     * boolean pred(int i, int acc, int k) { return i < k; }
        -     * int fin(int i, int acc, int k) { return acc; }
        +     * static int inc(int i, int acc, int k) { return i + 1; }
        +     * static int mult(int i, int acc, int k) { return i * acc; }
        +     * static boolean pred(int i, int acc, int k) { return i < k; }
        +     * static int fin(int i, int acc, int k) { return acc; }
              * // assume MH_one, MH_inc, MH_mult, MH_pred, and MH_fin are handles to the above methods
              * // null initializer for counter, should initialize to 0
              * MethodHandle[] counterClause = new MethodHandle[]{null, MH_inc};
        @@ -3436,9 +3438,7 @@
                         collect(Collectors.toList());
         
                 // Step 1B: determine loop parameters.
        -        final List> empty = new ArrayList<>();
        -        final List> commonSuffix = init.stream().filter(Objects::nonNull).map(MethodHandle::type).
        -                map(MethodType::parameterList).reduce((p, q) -> p.size() >= q.size() ? p : q).orElse(empty);
        +        final List> commonSuffix = buildCommonSuffix(init, step, pred, fini, commonPrefix.size());
                 checkLoop1b(init, commonSuffix);
         
                 // Step 1C: determine loop return type.
        @@ -3520,9 +3520,9 @@
              * @apiNote Example:
              * 
        {@code
              * // implement the zip function for lists as a loop handle
        -     * List initZip(Iterator a, Iterator b) { return new ArrayList<>(); }
        -     * boolean zipPred(List zip, Iterator a, Iterator b) { return a.hasNext() && b.hasNext(); }
        -     * List zipStep(List zip, Iterator a, Iterator b) {
        +     * static List initZip(Iterator a, Iterator b) { return new ArrayList<>(); }
        +     * static boolean zipPred(List zip, Iterator a, Iterator b) { return a.hasNext() && b.hasNext(); }
        +     * static List zipStep(List zip, Iterator a, Iterator b) {
              *   zip.add(a.next());
              *   zip.add(b.next());
              *   return zip;
        @@ -3594,9 +3594,9 @@
              * @apiNote Example:
              * 
        {@code
              * // int i = 0; while (i < limit) { ++i; } return i; => limit
        -     * int zero(int limit) { return 0; }
        -     * int step(int i, int limit) { return i + 1; }
        -     * boolean pred(int i, int limit) { return i < limit; }
        +     * static int zero(int limit) { return 0; }
        +     * static int step(int i, int limit) { return i + 1; }
        +     * static boolean pred(int i, int limit) { return i < limit; }
              * // assume MH_zero, MH_step, and MH_pred are handles to the above methods
              * MethodHandle loop = MethodHandles.doWhileLoop(MH_zero, MH_step, MH_pred);
              * assertEquals(23, loop.invoke(23));
        @@ -3664,8 +3664,8 @@
              * 
        {@code
              * // String s = "Lambdaman!"; for (int i = 0; i < 13; ++i) { s = "na " + s; } return s;
              * // => a variation on a well known theme
        -     * String start(String arg) { return arg; }
        -     * String step(int counter, String v, String arg) { return "na " + v; }
        +     * static String start(String arg) { return arg; }
        +     * static String step(int counter, String v, String arg) { return "na " + v; }
              * // assume MH_start and MH_step are handles to the two methods above
              * MethodHandle fit13 = MethodHandles.constant(int.class, 13);
              * MethodHandle loop = MethodHandles.countedLoop(fit13, MH_start, MH_step);
        @@ -3808,11 +3808,11 @@
              * @apiNote Example:
              * 
        {@code
              * // reverse a list
        -     * List reverseStep(String e, List r, List l) {
        +     * static List reverseStep(String e, List r, List l) {
              *   r.add(0, e);
              *   return r;
              * }
        -     * List newArrayList(List l) { return new ArrayList<>(); }
        +     * static List newArrayList(List l) { return new ArrayList<>(); }
              * // assume MH_reverseStep, MH_newArrayList are handles to the above methods
              * MethodHandle loop = MethodHandles.iteratedLoop(null, MH_newArrayList, MH_reverseStep);
              * List list = Arrays.asList("a", "b", "c", "d", "e");
        @@ -4084,6 +4084,21 @@
                 }
             }
         
        +    private static List> buildCommonSuffix(List init, List step, List pred, List fini, int cpSize) {
        +        final List> empty = List.of();
        +        final List nonNullInits = init.stream().filter(Objects::nonNull).collect(Collectors.toList());
        +        if (nonNullInits.isEmpty()) {
        +            final List> longest = Stream.of(step, pred, fini).flatMap(List::stream).filter(Objects::nonNull).
        +                    // take only those that can contribute to a common suffix because they are longer than the prefix
        +                    map(MethodHandle::type).filter(t -> t.parameterCount() > cpSize).map(MethodType::parameterList).
        +                    reduce((p, q) -> p.size() >= q.size() ? p : q).orElse(empty);
        +            return longest.size() == 0 ? empty : longest.subList(cpSize, longest.size());
        +        } else {
        +            return nonNullInits.stream().map(MethodHandle::type).map(MethodType::parameterList).
        +                    reduce((p, q) -> p.size() >= q.size() ? p : q).get();
        +        }
        +    }
        +
             private static void checkLoop1b(List init, List> commonSuffix) {
                 if (init.stream().filter(Objects::nonNull).map(MethodHandle::type).map(MethodType::parameterList).
                         anyMatch(pl -> !pl.equals(commonSuffix.subList(0, pl.size())))) {
        @@ -4109,8 +4124,10 @@
             }
         
             private static void checkLoop2(List step, List pred, List fini, List> commonParameterSequence) {
        +        final int cpSize = commonParameterSequence.size();
                 if (Stream.of(step, pred, fini).flatMap(List::stream).filter(Objects::nonNull).map(MethodHandle::type).
        -                map(MethodType::parameterList).anyMatch(pl -> !pl.equals(commonParameterSequence.subList(0, pl.size())))) {
        +                map(MethodType::parameterList).
        +                anyMatch(pl -> pl.size() > cpSize || !pl.equals(commonParameterSequence.subList(0, pl.size())))) {
                     throw newIllegalArgumentException("found non-effectively identical parameter type lists:\nstep: " + step +
                             "\npred: " + pred + "\nfini: " + fini + " (common parameter sequence: " + commonParameterSequence + ")");
                 }