8153637: MethodHandles.countedLoop/3 initialises loop counter to 1 instead of 0
Reviewed-by: psandoz, redestad
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java Wed Apr 13 00:00:39 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java Wed Apr 13 09:20:22 2016 +0200
@@ -1754,6 +1754,18 @@
}
/**
+ * This method is bound as a filter in {@linkplain MethodHandles#countedLoop(MethodHandle, MethodHandle, MethodHandle,
+ * MethodHandle) counting loops} to pass the correct counter value to the body.
+ *
+ * @param counter the loop counter.
+ *
+ * @return the loop counter decremented by 1.
+ */
+ static int decrementCounter(int counter) {
+ return counter - 1;
+ }
+
+ /**
* This is bound to initialize the loop-local iterator in {@linkplain MethodHandles#iteratedLoop iterating loops}.
*
* @param it the {@link Iterable} over which the loop iterates.
@@ -1879,7 +1891,8 @@
MH_iterateNext = 11,
MH_tryFinallyExec = 12,
MH_tryFinallyVoidExec = 13,
- MH_LIMIT = 14;
+ MH_decrementCounter = 14,
+ MH_LIMIT = 15;
static MethodHandle getConstantHandle(int idx) {
MethodHandle handle = HANDLES[idx];
@@ -1949,6 +1962,9 @@
case MH_tryFinallyVoidExec:
return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "tryFinallyVoidExecutor",
MethodType.methodType(void.class, MethodHandle.class, MethodHandle.class, Object[].class));
+ case MH_decrementCounter:
+ return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "decrementCounter",
+ MethodType.methodType(int.class, int.class));
}
} catch (ReflectiveOperationException ex) {
throw newInternalError(ex);
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java Wed Apr 13 00:00:39 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java Wed Apr 13 09:20:22 2016 +0200
@@ -4322,11 +4322,13 @@
* <blockquote><pre>{@code
* MethodHandle countedLoop(MethodHandle start, MethodHandle end, MethodHandle init, MethodHandle body) {
* MethodHandle returnVar = dropArguments(identity(init.type().returnType()), 0, int.class, int.class);
- * // assume MH_increment and MH_lessThan are handles to x+1 and x<y of type int
+ * // assume MH_increment and MH_lessThan are handles to x+1 and x<y of type int,
+ * // assume MH_decrement is a handle to x-1 of type int
* MethodHandle[]
* indexVar = {start, MH_increment}, // i = start; i = i+1
* loopLimit = {end, null, MH_lessThan, returnVar }, // i<end
- * bodyClause = {init, dropArguments(body, 1, int.class)}; // v = body(i, v);
+ * bodyClause = {init,
+ * filterArgument(dropArguments(body, 1, int.class), 0, MH_decrement}; // v = body(i-1, v)
* return loop(indexVar, loopLimit, bodyClause);
* }
* }</pre></blockquote>
@@ -4351,7 +4353,9 @@
0, int.class, int.class);
MethodHandle[] indexVar = {start, MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_countedLoopStep)};
MethodHandle[] loopLimit = {end, null, MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_countedLoopPred), returnVar};
- MethodHandle[] bodyClause = {init, dropArguments(body, 1, int.class)};
+ MethodHandle[] bodyClause = {init,
+ filterArgument(dropArguments(body, 1, int.class), 0,
+ MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_decrementCounter))};
return loop(indexVar, loopLimit, bodyClause);
}
--- a/jdk/test/java/lang/invoke/LoopCombinatorTest.java Wed Apr 13 00:00:39 2016 -0700
+++ b/jdk/test/java/lang/invoke/LoopCombinatorTest.java Wed Apr 13 09:20:22 2016 +0200
@@ -26,6 +26,8 @@
/* @test
* @bug 8139885
* @bug 8150635
+ * @bug 8150957
+ * @bug 8153637
* @run testng/othervm -ea -esa test.java.lang.invoke.LoopCombinatorTest
*/
@@ -302,6 +304,18 @@
}
@Test
+ public static void testCountedLoopCounterInit() throws Throwable {
+ // int x = 0; for (int i = 0; i < 5; ++i) { x += i; } return x; => 10
+ // (only if counter's first value in body is 0)
+ MethodHandle iter = MethodHandles.constant(int.class, 5);
+ MethodHandle init = MethodHandles.constant(int.class, 0);
+ MethodHandle body = Counted.MH_addCounter;
+ MethodHandle loop = MethodHandles.countedLoop(iter, init, body);
+ assertEquals(Counted.MT_counterInit, loop.type());
+ assertEquals(10, loop.invoke());
+ }
+
+ @Test
public static void testIterateSum() throws Throwable {
// Integer[] a = new Integer[]{1,2,3,4,5,6}; int sum = 0; for (int e : a) { sum += e; } return sum; => 21
MethodHandle loop = MethodHandles.iteratedLoop(Iterate.MH_sumIterator, Iterate.MH_sumInit, Iterate.MH_sumStep);
@@ -667,12 +681,17 @@
System.out.print("hello");
}
+ static int addCounter(int counter, int x) {
+ return x + counter;
+ }
+
static final Class<Counted> COUNTED = Counted.class;
static final MethodType MT_start = methodType(String.class, String.class);
static final MethodType MT_step = methodType(String.class, int.class, String.class, String.class);
static final MethodType MT_stepUpdateArray = methodType(void.class, int.class, int[].class);
static final MethodType MT_printHello = methodType(void.class, int.class);
+ static final MethodType MT_addCounter = methodType(int.class, int.class, int.class);
static final MethodHandle MH_13;
static final MethodHandle MH_m5;
@@ -681,10 +700,12 @@
static final MethodHandle MH_step;
static final MethodHandle MH_stepUpdateArray;
static final MethodHandle MH_printHello;
+ static final MethodHandle MH_addCounter;
static final MethodType MT_counted = methodType(String.class, String.class);
static final MethodType MT_arrayCounted = methodType(void.class, int[].class);
static final MethodType MT_countedPrinting = methodType(void.class);
+ static final MethodType MT_counterInit = methodType(int.class);
static {
try {
@@ -695,6 +716,7 @@
MH_step = LOOKUP.findStatic(COUNTED, "step", MT_step);
MH_stepUpdateArray = LOOKUP.findStatic(COUNTED, "stepUpdateArray", MT_stepUpdateArray);
MH_printHello = LOOKUP.findStatic(COUNTED, "printHello", MT_printHello);
+ MH_addCounter = LOOKUP.findStatic(COUNTED, "addCounter", MT_addCounter);
} catch (Exception e) {
throw new ExceptionInInitializerError(e);
}