< prev index next >
test/java/lang/invoke/T8139885.java
Print this page
rev 13791 : 8150635: j.l.i.MethodHandles.loop(...) throws IndexOutOfBoundsException
Reviewed-by: psandoz
*** 25,34 ****
--- 25,35 ----
/* @test
* @bug 8139885
* @bug 8143798
* @bug 8150825
+ * @bug 8150635
* @run testng/othervm -ea -esa test.java.lang.invoke.T8139885
*/
package test.java.lang.invoke;
*** 75,84 ****
--- 76,94 ----
assertEquals(Fac.MT_fac, loop.type());
assertEquals(120, loop.invoke(5));
}
@Test
+ public static void testLoopNullInit() throws Throwable {
+ // null initializer for counter, should initialize to 0, one-clause loop
+ MethodHandle[] counterClause = new MethodHandle[]{null, Loop.MH_inc, Loop.MH_pred, Loop.MH_fin};
+ MethodHandle loop = MethodHandles.loop(counterClause);
+ assertEquals(Loop.MT_loop, loop.type());
+ assertEquals(10, loop.invoke(10));
+ }
+
+ @Test
public static void testLoopVoid1() throws Throwable {
// construct a post-checked loop that only does one iteration and has a void body and void local state
MethodHandle loop = MethodHandles.loop(new MethodHandle[]{Empty.MH_f, Empty.MH_f, Empty.MH_pred, null});
assertEquals(MethodType.methodType(void.class), loop.type());
loop.invoke();
*** 92,101 ****
--- 102,120 ----
assertEquals(MethodType.methodType(void.class), loop.type());
loop.invoke();
}
@Test
+ public static void testLoopVoid3() throws Throwable {
+ // construct a post-checked loop that only does one iteration and has a void body and void local state,
+ // and that has a void finalizer
+ MethodHandle loop = MethodHandles.loop(new MethodHandle[]{null, Empty.MH_f, Empty.MH_pred, Empty.MH_f});
+ assertEquals(MethodType.methodType(void.class), loop.type());
+ loop.invoke();
+ }
+
+ @Test
public static void testLoopFacWithVoidState() throws Throwable {
// like testLoopFac, but with additional void state that outputs a dot
MethodHandle[] counterClause = new MethodHandle[]{Fac.MH_zero, Fac.MH_inc};
MethodHandle[] accumulatorClause = new MethodHandle[]{Fac.MH_one, Fac.MH_mult, Fac.MH_pred, Fac.MH_fin};
MethodHandle[] dotClause = new MethodHandle[]{null, Fac.MH_dot};
*** 103,112 ****
--- 122,156 ----
assertEquals(Fac.MT_fac, loop.type());
assertEquals(120, loop.invoke(5));
}
@Test
+ public static void testLoopVoidInt() throws Throwable {
+ // construct a post-checked loop that only does one iteration and has a void body and void local state,
+ // and that returns a constant
+ MethodHandle loop = MethodHandles.loop(new MethodHandle[]{null, Empty.MH_f, Empty.MH_pred, Empty.MH_c});
+ assertEquals(MethodType.methodType(int.class), loop.type());
+ assertEquals(23, loop.invoke());
+ }
+
+ @Test
+ public static void testLoopWithVirtuals() throws Throwable {
+ // construct a loop (to calculate factorial) that uses a mix of static and virtual methods
+ MethodHandle[] counterClause = new MethodHandle[]{null, LoopWithVirtuals.permute(LoopWithVirtuals.MH_inc)};
+ MethodHandle[] accumulatorClause = new MethodHandle[]{
+ // init function must indicate the loop arguments (there is no other means to determine them)
+ MethodHandles.dropArguments(LoopWithVirtuals.MH_one, 0, LoopWithVirtuals.class),
+ LoopWithVirtuals.permute(LoopWithVirtuals.MH_mult),
+ LoopWithVirtuals.permute(LoopWithVirtuals.MH_pred),
+ LoopWithVirtuals.permute(LoopWithVirtuals.MH_fin)
+ };
+ MethodHandle loop = MethodHandles.loop(counterClause, accumulatorClause);
+ assertEquals(LoopWithVirtuals.MT_loop, loop.type());
+ assertEquals(120, loop.invoke(new LoopWithVirtuals(), 5));
+ }
+
+ @Test
public static void testLoopNegative() throws Throwable {
MethodHandle mh_loop =
LOOKUP.findStatic(MethodHandles.class, "loop", methodType(MethodHandle.class, MethodHandle[][].class));
MethodHandle i0 = MethodHandles.constant(int.class, 0);
MethodHandle ii = MethodHandles.dropArguments(i0, 0, int.class, int.class);
*** 119,153 ****
List<MethodHandle> preds2 = Arrays.asList(null, Fac.MH_fin, null);
MethodHandle eek = MethodHandles.dropArguments(i0, 0, int.class, int.class, double.class);
List<MethodHandle> nesteps = Arrays.asList(Fac.MH_inc, eek, Fac.MH_dot);
List<MethodHandle> nepreds = Arrays.asList(null, Fac.MH_pred, null);
List<MethodHandle> nefinis = Arrays.asList(null, Fac.MH_fin, null);
MethodHandle[][][] cases = {
! null,
! {},
! {{null, Fac.MH_inc}, {Fac.MH_one, null, Fac.MH_mult, Fac.MH_pred, Fac.MH_fin}},
! {{null, Fac.MH_inc}, null},
! {{Fac.MH_zero, Fac.MH_dot}},
! {{ii}, {id}, {i3}},
! {{null, Fac.MH_inc, null, Fac.MH_fin}, {null, Fac.MH_inc, null, Fac.MH_inc},
{null, Counted.MH_start, null, Counted.MH_step}},
! {{Fac.MH_zero, Fac.MH_inc}, {Fac.MH_one, Fac.MH_mult, null, Fac.MH_fin}, {null, Fac.MH_dot}},
! {{Fac.MH_zero, Fac.MH_inc}, {Fac.MH_one, Fac.MH_mult, Fac.MH_fin, Fac.MH_fin}, {null, Fac.MH_dot}},
! {{Fac.MH_zero, Fac.MH_inc}, {Fac.MH_one, eek, Fac.MH_pred, Fac.MH_fin}, {null, Fac.MH_dot}}
};
String[] messages = {
! "null or no clauses passed",
! "null or no clauses passed",
! "All loop clauses must be represented as MethodHandle arrays with at most 4 elements.",
! "null clauses are not allowed",
! "clause 0: init and step return types must match: int != void",
! "found non-effectively identical init parameter type lists: " + inits + " (common suffix: " + ints + ")",
! "found non-identical finalizer return types: " + finis + " (return type: int)",
! "no predicate found: " + preds1,
! "predicates must have boolean return type: " + preds2,
! "found non-effectively identical parameter type lists:\nstep: " + nesteps + "\npred: " + nepreds +
! "\nfini: " + nefinis + " (common parameter sequence: " + ints + ")"
};
for (int i = 0; i < cases.length; ++i) {
boolean caught = false;
try {
mh_loop.invokeWithArguments(cases[i]);
--- 163,204 ----
List<MethodHandle> preds2 = Arrays.asList(null, Fac.MH_fin, null);
MethodHandle eek = MethodHandles.dropArguments(i0, 0, int.class, int.class, double.class);
List<MethodHandle> nesteps = Arrays.asList(Fac.MH_inc, eek, Fac.MH_dot);
List<MethodHandle> nepreds = Arrays.asList(null, Fac.MH_pred, null);
List<MethodHandle> nefinis = Arrays.asList(null, Fac.MH_fin, null);
+ List<MethodHandle> lvsteps = Arrays.asList(LoopWithVirtuals.MH_inc, LoopWithVirtuals.MH_mult);
+ List<MethodHandle> lvpreds = Arrays.asList(null, LoopWithVirtuals.MH_pred);
+ List<MethodHandle> lvfinis = Arrays.asList(null, LoopWithVirtuals.MH_fin);
MethodHandle[][][] cases = {
! /* 1 */ null,
! /* 2 */ {},
! /* 3 */ {{null, Fac.MH_inc}, {Fac.MH_one, null, Fac.MH_mult, Fac.MH_pred, Fac.MH_fin}},
! /* 4 */ {{null, Fac.MH_inc}, null},
! /* 5 */ {{Fac.MH_zero, Fac.MH_dot}},
! /* 6 */ {{ii}, {id}, {i3}},
! /* 7 */ {{null, Fac.MH_inc, null, Fac.MH_fin}, {null, Fac.MH_inc, null, Fac.MH_inc},
{null, Counted.MH_start, null, Counted.MH_step}},
! /* 8 */ {{Fac.MH_zero, Fac.MH_inc}, {Fac.MH_one, Fac.MH_mult, null, Fac.MH_fin}, {null, Fac.MH_dot}},
! /* 9 */ {{Fac.MH_zero, Fac.MH_inc}, {Fac.MH_one, Fac.MH_mult, Fac.MH_fin, Fac.MH_fin}, {null, Fac.MH_dot}},
! /* 10 */ {{Fac.MH_zero, Fac.MH_inc}, {Fac.MH_one, eek, Fac.MH_pred, Fac.MH_fin}, {null, Fac.MH_dot}},
! /* 11 */ {{null, LoopWithVirtuals.MH_inc}, {LoopWithVirtuals.MH_one, LoopWithVirtuals.MH_mult, LoopWithVirtuals.MH_pred, LoopWithVirtuals.MH_fin}}
};
String[] messages = {
! /* 1 */ "null or no clauses passed",
! /* 2 */ "null or no clauses passed",
! /* 3 */ "All loop clauses must be represented as MethodHandle arrays with at most 4 elements.",
! /* 4 */ "null clauses are not allowed",
! /* 5 */ "clause 0: init and step return types must match: int != void",
! /* 6 */ "found non-effectively identical init parameter type lists: " + inits +
! " (common suffix: " + ints + ")",
! /* 7 */ "found non-identical finalizer return types: " + finis + " (return type: int)",
! /* 8 */ "no predicate found: " + preds1,
! /* 9 */ "predicates must have boolean return type: " + preds2,
! /* 10 */ "found non-effectively identical parameter type lists:\nstep: " + nesteps +
! "\npred: " + nepreds + "\nfini: " + nefinis + " (common parameter sequence: " + ints + ")",
! /* 11 */ "found non-effectively identical parameter type lists:\nstep: " + lvsteps +
! "\npred: " + lvpreds + "\nfini: " + lvfinis + " (common parameter sequence: " + ints + ")"
};
for (int i = 0; i < cases.length; ++i) {
boolean caught = false;
try {
mh_loop.invokeWithArguments(cases[i]);
*** 568,589 ****
--- 619,647 ----
static boolean pred() {
return false;
}
+ static int c() {
+ return 23;
+ }
+
static final Class<Empty> EMPTY = Empty.class;
static final MethodType MT_f = methodType(void.class);
static final MethodType MT_pred = methodType(boolean.class);
+ static final MethodType MT_c = methodType(int.class);
static final MethodHandle MH_f;
static final MethodHandle MH_pred;
+ static final MethodHandle MH_c;
static {
try {
MH_f = LOOKUP.findStatic(EMPTY, "f", MT_f);
MH_pred = LOOKUP.findStatic(EMPTY, "pred", MT_pred);
+ MH_c = LOOKUP.findStatic(EMPTY, "c", MT_c);
} catch (Exception e) {
throw new ExceptionInInitializerError(e);
}
}
}
*** 649,658 ****
--- 707,814 ----
}
}
}
+ static class Loop {
+
+ static int inc(int i, int k) {
+ return i + 1;
+ }
+
+ static boolean pred(int i, int k) {
+ return i < k;
+ }
+
+ static int fin(int i, int k) {
+ return k;
+ }
+
+ static final Class<Loop> LOOP = Loop.class;
+
+ static final MethodType MT_inc = methodType(int.class, int.class, int.class);
+ static final MethodType MT_pred = methodType(boolean.class, int.class, int.class);
+ static final MethodType MT_fin = methodType(int.class, int.class, int.class);
+
+ static final MethodHandle MH_inc;
+ static final MethodHandle MH_pred;
+ static final MethodHandle MH_fin;
+
+ static final MethodType MT_loop = methodType(int.class, int.class);
+
+ static {
+ try {
+ MH_inc = LOOKUP.findStatic(LOOP, "inc", MT_inc);
+ MH_pred = LOOKUP.findStatic(LOOP, "pred", MT_pred);
+ MH_fin = LOOKUP.findStatic(LOOP, "fin", MT_fin);
+ } catch (Exception e) {
+ throw new ExceptionInInitializerError(e);
+ }
+ }
+
+ }
+
+ static class LoopWithVirtuals {
+
+ 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 final Class<LoopWithVirtuals> LOOP_WITH_VIRTUALS = LoopWithVirtuals.class;
+
+ static final MethodType MT_one = methodType(int.class, int.class);
+ static final MethodType MT_inc = methodType(int.class, int.class, int.class, int.class);
+ static final MethodType MT_mult = methodType(int.class, int.class, int.class, int.class);
+ static final MethodType MT_pred = methodType(boolean.class, int.class, int.class, int.class);
+ static final MethodType MT_fin = methodType(int.class, int.class, int.class, int.class);
+
+ static final MethodHandle MH_one;
+ static final MethodHandle MH_inc;
+ static final MethodHandle MH_mult;
+ static final MethodHandle MH_pred;
+ static final MethodHandle MH_fin;
+
+ static final MethodType MT_loop = methodType(int.class, LOOP_WITH_VIRTUALS, int.class);
+
+ static {
+ try {
+ MH_one = LOOKUP.findStatic(LOOP_WITH_VIRTUALS, "one", MT_one);
+ MH_inc = LOOKUP.findVirtual(LOOP_WITH_VIRTUALS, "inc", MT_inc);
+ MH_mult = LOOKUP.findVirtual(LOOP_WITH_VIRTUALS, "mult", MT_mult);
+ MH_pred = LOOKUP.findVirtual(LOOP_WITH_VIRTUALS, "pred", MT_pred);
+ MH_fin = LOOKUP.findVirtual(LOOP_WITH_VIRTUALS, "fin", MT_fin);
+ } catch (Exception e) {
+ throw new ExceptionInInitializerError(e);
+ }
+ }
+
+ static MethodHandle permute(MethodHandle h) {
+ // The handles representing virtual methods need to be rearranged to match the required order of arguments
+ // (loop-local state comes first, then loop arguments). As the receiver comes first in the signature but is
+ // a loop argument, it must be moved to the appropriate position in the signature.
+ return MethodHandles.permuteArguments(h,
+ methodType(h.type().returnType(), int.class, int.class, LOOP_WITH_VIRTUALS, int.class), 2, 0, 1, 3);
+ }
+
+ }
+
static class While {
static int zero(int limit) {
return 0;
}
< prev index next >