8167974: MethodHandles.iteratedLoop(...) fails with CCE in the case of iterating over array

8167966: MethodHandles.iteratedLoop fails with IAE in the case of correct arguments

Reviewed-by: redestad
This commit is contained in:
Paul Sandoz 2016-11-01 17:29:48 -07:00
parent 674c5463e3
commit 1730680ce7
2 changed files with 37 additions and 24 deletions

View File

@ -5347,7 +5347,7 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
* {@code (V T A...)} must have at least one {@code A} type, and the default iterator
* handle parameter is adjusted to accept the leading {@code A} type, as if by
* the {@link MethodHandle#asType asType} conversion method.
* The leading {@code A} type must be {@code Iterable} or a subtype thereof, or an array type.
* The leading {@code A} type must be {@code Iterable} or a subtype thereof.
* This conversion step, done at loop construction time, must not throw a {@code WrongMethodTypeException}.
* </ul>
* <p>
@ -5374,7 +5374,8 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
* V iteratedLoop(A... a...) {
* Iterator<T> it = iterator(a...);
* V v = init(a...);
* for (T t : it) {
* while (it.hasNext()) {
* T t = it.next();
* v = body(v, t, a...);
* }
* return v;
@ -5483,49 +5484,59 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
Objects.requireNonNull(body);
MethodType bodyType = body.type();
Class<?> returnType = bodyType.returnType();
List<Class<?>> innerList = bodyType.parameterList();
List<Class<?>> internalParamList = bodyType.parameterList();
// strip leading V value if present
int vsize = (returnType == void.class ? 0 : 1);
if (vsize != 0 && (innerList.size() == 0 || innerList.get(0) != returnType)) {
if (vsize != 0 && (internalParamList.size() == 0 || internalParamList.get(0) != returnType)) {
// argument list has no "V" => error
MethodType expected = bodyType.insertParameterTypes(0, returnType);
throw misMatchedTypes("body function", bodyType, expected);
} else if (innerList.size() <= vsize) {
} else if (internalParamList.size() <= vsize) {
// missing T type => error
MethodType expected = bodyType.insertParameterTypes(vsize, Object.class);
throw misMatchedTypes("body function", bodyType, expected);
}
//Class<?> elementType = innerList.get(vsize); // do not need this
List<Class<?>> outerList = innerList.subList(vsize + 1, innerList.size());
if (outerList.isEmpty()) {
// special case; take lists from iterator handle
outerList = ((iterator != null)
? iterator.type().parameterList()
: Arrays.asList(Iterable.class));
innerList = bodyType.insertParameterTypes(vsize + 1, outerList).parameterList();
}
List<Class<?>> externalParamList = internalParamList.subList(vsize + 1, internalParamList.size());
Class<?> iterableType = null;
if (iterator != null) {
// special case; if the body handle only declares V and T then
// the external parameter list is obtained from iterator handle
if (externalParamList.isEmpty()) {
externalParamList = iterator.type().parameterList();
}
MethodType itype = iterator.type();
if (!Iterator.class.isAssignableFrom(itype.returnType())) {
throw newIllegalArgumentException("iteratedLoop first argument must have Iterator return type");
}
if (!itype.effectivelyIdenticalParameters(0, outerList)) {
MethodType expected = methodType(itype.returnType(), outerList);
if (!itype.effectivelyIdenticalParameters(0, externalParamList)) {
MethodType expected = methodType(itype.returnType(), externalParamList);
throw misMatchedTypes("iterator parameters", itype, expected);
}
} else {
if (externalParamList.isEmpty()) {
// special case; if the iterator handle is null and the body handle
// only declares V and T then the external parameter list consists
// of Iterable
externalParamList = Arrays.asList(Iterable.class);
iterableType = Iterable.class;
} else {
// special case; if the iterator handle is null and the external
// parameter list is not empty then the first parameter must be
// assignable to Iterable
iterableType = externalParamList.get(0);
if (!Iterable.class.isAssignableFrom(iterableType)) {
throw newIllegalArgumentException(
"inferred first loop argument must inherit from Iterable: " + iterableType);
}
}
}
if (init != null) {
MethodType initType = init.type();
if (initType.returnType() != returnType ||
!initType.effectivelyIdenticalParameters(0, outerList)) {
throw misMatchedTypes("loop initializer", initType, methodType(returnType, outerList));
!initType.effectivelyIdenticalParameters(0, externalParamList)) {
throw misMatchedTypes("loop initializer", initType, methodType(returnType, externalParamList));
}
}
Class<?> iterableType = outerList.isEmpty() ? null : outerList.get(0);
if (iterableType != null && !Iterable.class.isAssignableFrom(iterableType) && !iterableType.isArray()) {
throw newIllegalArgumentException(
"inferred first loop argument must be an array or inherit from Iterable: " + iterableType);
}
return iterableType; // help the caller a bit
}

View File

@ -33,6 +33,7 @@
* @bug 8153637
* @bug 8154751
* @bug 8154754
* @bug 8167974
* @run testng/othervm -ea -esa test.java.lang.invoke.LoopCombinatorTest
*/
@ -800,7 +801,8 @@ public class LoopCombinatorTest {
{l_it, l_i, isl_i, ""},
{l_it, null, sl_v, ""},
{li_it, li_i, isli_i, ""},
{il_it, null, sil_v, "inferred first loop argument must inherit from Iterable: int"},
{null, null, sil_v, "inferred first loop argument must inherit from Iterable: int"},
{il_it, null, sil_v, ""},
{li_it, null, sli_v, ""},
{sl_v, null, sl_v, "iteratedLoop first argument must have Iterator return type"},
{li_it, l_it, sl_v,