--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java Wed Mar 02 16:25:29 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java Wed Mar 02 20:16:11 2016 +0100
@@ -3268,12 +3268,17 @@
* <li>This list of types is called the "common prefix".
* </ol>
* <p>
- * <em>Step 1B: Determine loop parameters.</em><ol type="a">
- * <li>Examine init function parameter lists.
- * <li>Omitted init functions are deemed to have {@code null} parameter lists.
- * <li>All init function parameter lists must be effectively identical.
- * <li>The longest parameter list (which is necessarily unique) is called the "common suffix".
+ * <em>Step 1B: Determine loop parameters.</em><ul>
+ * <li><b>If at least one init function is given,</b><ol type="a">
+ * <li>Examine init function parameter lists.
+ * <li>Omitted init functions are deemed to have {@code null} parameter lists.
+ * <li>All init function parameter lists must be effectively identical.
+ * <li>The longest parameter list (which is necessarily unique) is called the "common suffix".
* </ol>
+ * <li><b>If no init function is given,</b><ol type="a">
+ * <li>Examine the suffixes of the step, pred, and fini parameter lists, after removing the "common prefix".
+ * <li>The longest of these suffixes is taken as the "common suffix".
+ * </ol></ul>
* <p>
* <em>Step 1C: Determine loop return type.</em><ol type="a">
* <li>Examine fini function return types, disregarding omitted fini functions.
@@ -3286,9 +3291,6 @@
* <li>Every non-omitted pred function must have a {@code boolean} return type.
* </ol>
* <p>
- * (Implementation Note: Steps 1A, 1B, 1C, 1D are logically independent of each other, and may be performed in any
- * order.)
- * <p>
* <em>Step 2: Determine parameter lists.</em><ol type="a">
* <li>The parameter list for the resulting loop handle will be the "common suffix".
* <li>The parameter list for init functions will be adjusted to the "common suffix". (Note that their parameter
@@ -3375,10 +3377,10 @@
* <blockquote><pre>{@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<Class<?>> empty = new ArrayList<>();
- final List<Class<?>> 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<Class<?>> commonSuffix = buildCommonSuffix(init, step, pred, fini, commonPrefix.size());
checkLoop1b(init, commonSuffix);
// Step 1C: determine loop return type.
@@ -3520,9 +3520,9 @@
* @apiNote Example:
* <blockquote><pre>{@code
* // implement the zip function for lists as a loop handle
- * List<String> initZip(Iterator<String> a, Iterator<String> b) { return new ArrayList<>(); }
- * boolean zipPred(List<String> zip, Iterator<String> a, Iterator<String> b) { return a.hasNext() && b.hasNext(); }
- * List<String> zipStep(List<String> zip, Iterator<String> a, Iterator<String> b) {
+ * static List<String> initZip(Iterator<String> a, Iterator<String> b) { return new ArrayList<>(); }
+ * static boolean zipPred(List<String> zip, Iterator<String> a, Iterator<String> b) { return a.hasNext() && b.hasNext(); }
+ * static List<String> zipStep(List<String> zip, Iterator<String> a, Iterator<String> b) {
* zip.add(a.next());
* zip.add(b.next());
* return zip;
@@ -3594,9 +3594,9 @@
* @apiNote Example:
* <blockquote><pre>{@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 @@
* <blockquote><pre>{@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:
* <blockquote><pre>{@code
* // reverse a list
- * List<String> reverseStep(String e, List<String> r, List<String> l) {
+ * static List<String> reverseStep(String e, List<String> r, List<String> l) {
* r.add(0, e);
* return r;
* }
- * List<String> newArrayList(List<String> l) { return new ArrayList<>(); }
+ * static List<String> newArrayList(List<String> 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<String> list = Arrays.asList("a", "b", "c", "d", "e");
@@ -4084,6 +4084,21 @@
}
}
+ private static List<Class<?>> buildCommonSuffix(List<MethodHandle> init, List<MethodHandle> step, List<MethodHandle> pred, List<MethodHandle> fini, int cpSize) {
+ final List<Class<?>> empty = List.of();
+ final List<MethodHandle> nonNullInits = init.stream().filter(Objects::nonNull).collect(Collectors.toList());
+ if (nonNullInits.isEmpty()) {
+ final List<Class<?>> 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<MethodHandle> init, List<Class<?>> 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<MethodHandle> step, List<MethodHandle> pred, List<MethodHandle> fini, List<Class<?>> 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 + ")");
}