8153637: MethodHandles.countedLoop/3 initialises loop counter to 1 instead of 0
Reviewed-by: psandoz, redestad
This commit is contained in:
parent
fd0239a0bc
commit
c304110149
@ -1753,6 +1753,18 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
|
||||
return counter + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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}.
|
||||
*
|
||||
@ -1879,7 +1891,8 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
|
||||
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 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
|
||||
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);
|
||||
|
@ -4322,11 +4322,13 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
|
||||
* <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 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,8 @@
|
||||
/* @test
|
||||
* @bug 8139885
|
||||
* @bug 8150635
|
||||
* @bug 8150957
|
||||
* @bug 8153637
|
||||
* @run testng/othervm -ea -esa test.java.lang.invoke.LoopCombinatorTest
|
||||
*/
|
||||
|
||||
@ -301,6 +303,18 @@ public class LoopCombinatorTest {
|
||||
assertEquals("na na na na na na na na na na na na na Lambdaman!", loop.invoke("Lambdaman!"));
|
||||
}
|
||||
|
||||
@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
|
||||
@ -667,12 +681,17 @@ public class LoopCombinatorTest {
|
||||
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 @@ public class LoopCombinatorTest {
|
||||
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 @@ public class LoopCombinatorTest {
|
||||
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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user