Mercurial > hg > openjdk > jdk9 > jdk
changeset 14274:beac9a439d0f
8152667: MHs.iteratedLoop(...) throws unexpected WMTE, disallows Iterator subclasses, generates inconsistent loop result type
Reviewed-by: redestad
author | mhaupt |
---|---|
date | Fri, 22 Apr 2016 13:36:22 +0200 |
parents | 1781aba4f7e3 |
children | 14065c26ea1a |
files | src/java.base/share/classes/java/lang/invoke/MethodHandles.java test/java/lang/invoke/LoopCombinatorTest.java |
diffstat | 2 files changed, 94 insertions(+), 10 deletions(-) [+] |
line wrap: on
line diff
--- a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java Fri Apr 22 09:27:35 2016 +0000 +++ b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java Fri Apr 22 13:36:22 2016 +0200 @@ -4572,17 +4572,24 @@ */ public static MethodHandle iteratedLoop(MethodHandle iterator, MethodHandle init, MethodHandle body) { checkIteratedLoop(iterator, body); - final boolean voidInit = init == null || init.type().returnType() == void.class; + Class<?> resultType = init == null ? + body == null ? void.class : body.type().returnType() : + init.type().returnType(); + boolean voidResult = resultType == void.class; - MethodHandle initit = MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_initIterator); - MethodHandle initIterator = iterator == null ? - initit.asType(initit.type().changeParameterType(0, body.type().parameterType(voidInit ? 1 : 2))) : - iterator; - Class<?> itype = initIterator.type().returnType(); + MethodHandle initIterator; + if (iterator == null) { + MethodHandle initit = MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_initIterator); + initIterator = initit.asType(initit.type().changeParameterType(0, + body.type().parameterType(voidResult ? 1 : 2))); + } else { + initIterator = iterator.asType(iterator.type().changeReturnType(Iterator.class)); + } + Class<?> ttype = body.type().parameterType(0); MethodHandle returnVar = - dropArguments(voidInit ? zero(void.class) : identity(init.type().returnType()), 0, itype); + dropArguments(voidResult ? zero(void.class) : identity(resultType), 0, Iterator.class); MethodHandle initnx = MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_iterateNext); MethodHandle nextVal = initnx.asType(initnx.type().changeReturnType(ttype));
--- a/test/java/lang/invoke/LoopCombinatorTest.java Fri Apr 22 09:27:35 2016 +0000 +++ b/test/java/lang/invoke/LoopCombinatorTest.java Fri Apr 22 13:36:22 2016 +0200 @@ -28,6 +28,7 @@ * @bug 8150635 * @bug 8150956 * @bug 8150957 + * @bug 8152667 * @bug 8153637 * @run testng/othervm -ea -esa test.java.lang.invoke.LoopCombinatorTest */ @@ -400,10 +401,15 @@ assertTrue(caught); } - @Test - public static void testIterateVoidIterator() { + @DataProvider + static Object[][] wrongIteratorTypes() { + return new Object[][]{{void.class}, {Object.class}, {Iterable.class}}; + } + + @Test(dataProvider = "wrongIteratorTypes") + public static void testIterateVoidIterator(Class<?> it) { boolean caught = false; - MethodType v = methodType(void.class); + MethodType v = methodType(it); try { MethodHandles.iteratedLoop(MethodHandles.empty(v), null, MethodHandles.empty(v)); } catch(IllegalArgumentException iae) { @@ -420,6 +426,77 @@ loop.invoke(Arrays.asList("hello", "world")); } + @DataProvider + static Object[][] iterateParameters() { + MethodType i = methodType(int.class); + MethodType sil_i = methodType(int.class, String.class, int.class, List.class); + MethodType sl_v = methodType(void.class, String.class, List.class); + MethodType l_it = methodType(Iterator.class, List.class); + MethodType li_it = methodType(Iterator.class, List.class, int.class); + MethodType l_i = methodType(int.class, List.class); + MethodType _it = methodType(Iterator.class); + MethodType si_i = methodType(int.class, String.class, int.class); + MethodType s_i = methodType(int.class, String.class); + return new Object[][]{ + {null, null, sl_v}, + {null, i, sil_i}, + {null, l_i, sil_i}, + {l_it, null, sl_v}, + {l_it, i, sil_i}, + {li_it, l_i, sil_i}, + {l_it, null, sil_i}, + {li_it, null, sl_v}, + {_it, l_i, si_i}, + {_it, l_i, s_i} + }; + } + + @Test(dataProvider = "iterateParameters") + public static void testIterateParameters(MethodType it, MethodType in, MethodType bo) throws Throwable { + MethodHandle iterator = it == null ? null : MethodHandles.empty(it); + MethodHandle init = in == null ? null : MethodHandles.empty(in); + MethodHandle loop = MethodHandles.iteratedLoop(iterator, init, MethodHandles.empty(bo)); + MethodType lt = loop.type(); + if (it == null && in == null) { + assertEquals(bo.dropParameterTypes(0, 1), lt); + } else if (it == null) { + if (in.parameterCount() == 0) { + assertEquals(bo.dropParameterTypes(0, in.returnType() == void.class ? 1 : 2), lt); + } else { + assertEquals(methodType(bo.returnType(), in.parameterArray()), lt); + } + } else if (in == null) { + assertEquals(methodType(bo.returnType(), it.parameterArray()), lt); + } else if (it.parameterCount() > in.parameterCount()) { + assertEquals(methodType(bo.returnType(), it.parameterArray()), lt); + } else if (it.parameterCount() < in.parameterCount()) { + assertEquals(methodType(bo.returnType(), in.parameterArray()), lt); + } else { + // both it, in present; with equal parameter list lengths + assertEquals(it.parameterList(), lt.parameterList()); + assertEquals(in.parameterList(), lt.parameterList()); + assertEquals(bo.returnType(), lt.returnType()); + } + } + + @Test + public static void testIteratorSubclass() throws Throwable { + MethodHandle loop = MethodHandles.iteratedLoop(MethodHandles.empty(methodType(BogusIterator.class, List.class)), + null, MethodHandles.empty(methodType(void.class, String.class))); + assertEquals(methodType(void.class, List.class), loop.type()); + } + + static class BogusIterator implements Iterator { + @Override + public boolean hasNext() { + return false; + } + @Override + public Object next() { + return null; + } + } + static class Empty { static void f() { }