Mercurial > hg > openjdk > aarch64-port > jdk
changeset 10038:4b2bc06d521c
8057656: Improve MethodType.isCastableTo() & MethodType.isConvertibleTo() checks
Reviewed-by: vlivanov, psandoz
Contributed-by: john.r.rose@oracle.com
author | vlivanov |
---|---|
date | Wed, 10 Sep 2014 18:34:03 +0400 |
parents | 9d3feb922367 |
children | c9cc83fba300 |
files | src/share/classes/java/lang/invoke/MethodType.java |
diffstat | 1 files changed, 65 insertions(+), 6 deletions(-) [+] |
line wrap: on
line diff
--- a/src/share/classes/java/lang/invoke/MethodType.java Wed Sep 10 18:34:03 2014 +0400 +++ b/src/share/classes/java/lang/invoke/MethodType.java Wed Sep 10 18:34:03 2014 +0400 @@ -828,28 +828,87 @@ } /*non-public*/ boolean isCastableTo(MethodType newType) { + MethodTypeForm oldForm = this.form(); + MethodTypeForm newForm = newType.form(); + if (oldForm == newForm) + // same parameter count, same primitive/object mix + return true; int argc = parameterCount(); if (argc != newType.parameterCount()) return false; - return true; + // Corner case: boxing (primitive-to-reference) must have a plausible target type + // Therefore, we may have to return false for a boxing operation. + if (!canCast(returnType(), newType.returnType())) + return false; + if (newForm.primitiveParameterCount() == 0) + return true; // no primitive sources to mess things up + if (oldForm.erasedType == this) + return true; // no funny target references to mess things up + return canCastParameters(newType.ptypes, ptypes); } /*non-public*/ boolean isConvertibleTo(MethodType newType) { + MethodTypeForm oldForm = this.form(); + MethodTypeForm newForm = newType.form(); + if (oldForm == newForm) + // same parameter count, same primitive/object mix + return true; if (!canConvert(returnType(), newType.returnType())) return false; - int argc = parameterCount(); - if (argc != newType.parameterCount()) + Class<?>[] srcTypes = newType.ptypes; + Class<?>[] dstTypes = ptypes; + if (srcTypes == dstTypes) + return true; + int argc; + if ((argc = srcTypes.length) != dstTypes.length) return false; - for (int i = 0; i < argc; i++) { - if (!canConvert(newType.parameterType(i), parameterType(i))) + if (argc <= 1) { + if (argc == 1 && !canConvert(srcTypes[0], dstTypes[0])) return false; + return true; + } + if ((oldForm.primitiveParameterCount() == 0 && oldForm.erasedType == this) || + (newForm.primitiveParameterCount() == 0 && newForm.erasedType == newType)) { + // Somewhat complicated test to avoid a loop of 2 or more trips. + // If either type has only Object parameters, we know we can convert. + assert(canConvertParameters(srcTypes, dstTypes)); + return true; + } + return canConvertParameters(srcTypes, dstTypes); + } + + private boolean canCastParameters(Class<?>[] srcTypes, Class<?>[] dstTypes) { + for (int i = 0; i < srcTypes.length; i++) { + if (!canCast(srcTypes[i], dstTypes[i])) { + return false; + } } return true; } + + private boolean canConvertParameters(Class<?>[] srcTypes, Class<?>[] dstTypes) { + for (int i = 0; i < srcTypes.length; i++) { + if (!canConvert(srcTypes[i], dstTypes[i])) { + return false; + } + } + return true; + } + + private static boolean canCast(Class<?> src, Class<?> dst) { + if (src.isPrimitive() && !dst.isPrimitive()) { + if (dst == Object.class || dst.isInterface()) return true; + // Here is the corner case that is not castable. Example: int -> String + Wrapper sw = Wrapper.forPrimitiveType(src); + return dst.isAssignableFrom(sw.wrapperType()); + } + return true; + } + /*non-public*/ static boolean canConvert(Class<?> src, Class<?> dst) { // short-circuit a few cases: - if (src == dst || dst == Object.class) return true; + if (src == dst || src == Object.class || dst == Object.class) return true; // the remainder of this logic is documented in MethodHandle.asType if (src.isPrimitive()) { // can force void to an explicit null, a la reflect.Method.invoke