提交 a5a284b3 编写于 作者: V vlivanov

8058626: Missing part of 8057656 in 8u40 compared to 9

Reviewed-by: psandoz
上级 fd9d69e3
......@@ -2024,8 +2024,11 @@ return invoker;
*/
public static
MethodHandle explicitCastArguments(MethodHandle target, MethodType newType) {
if (!target.type().isCastableTo(newType)) {
throw new WrongMethodTypeException("cannot explicitly cast "+target+" to "+newType);
MethodType oldType = target.type();
// use the asTypeCache when possible:
if (oldType == newType) return target;
if (oldType.explicitCastEquivalentToAsType(newType)) {
return target.asType(newType);
}
return MethodHandleImpl.makePairwiseConvert(target, newType, false);
}
......
......@@ -827,26 +827,6 @@ class MethodType implements java.io.Serializable {
return true;
}
/*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;
// 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();
......@@ -877,15 +857,68 @@ class MethodType implements java.io.Serializable {
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])) {
/** Returns true if MHs.explicitCastArguments produces the same result as MH.asType.
* If the type conversion is impossible for either, the result should be false.
*/
/*non-public*/
boolean explicitCastEquivalentToAsType(MethodType newType) {
if (this == newType) return true;
if (!explicitCastEquivalentToAsType(rtype, newType.rtype)) {
return false;
}
Class<?>[] srcTypes = newType.ptypes;
Class<?>[] dstTypes = ptypes;
if (dstTypes == srcTypes) {
return true;
}
if (dstTypes.length != srcTypes.length) {
return false;
}
for (int i = 0; i < dstTypes.length; i++) {
if (!explicitCastEquivalentToAsType(srcTypes[i], dstTypes[i])) {
return false;
}
}
return true;
}
/** Reports true if the src can be converted to the dst, by both asType and MHs.eCE,
* and with the same effect.
* MHs.eCA has the following "upgrades" to MH.asType:
* 1. interfaces are unchecked (that is, treated as if aliased to Object)
* Therefore, {@code Object->CharSequence} is possible in both cases but has different semantics
* 2. the full matrix of primitive-to-primitive conversions is supported
* Narrowing like {@code long->byte} and basic-typing like {@code boolean->int}
* are not supported by asType, but anything supported by asType is equivalent
* with MHs.eCE.
* 3a. unboxing conversions can be followed by the full matrix of primitive conversions
* 3b. unboxing of null is permitted (creates a zero primitive value)
* Most unboxing conversions, like {@code Object->int}, has potentially
* different behaviors for asType vs. MHs.eCE, because the dynamic value
* might be a wrapper of a type that requires narrowing, like {@code (Object)1L->byte}.
* The equivalence is only certain if the static src type is a wrapper,
* and the conversion will be a widening one.
* Other than interfaces, reference-to-reference conversions are the same.
* Boxing primitives to references is the same for both operators.
*/
private static boolean explicitCastEquivalentToAsType(Class<?> src, Class<?> dst) {
if (src == dst || dst == Object.class || dst == void.class) return true;
if (src.isPrimitive()) {
// Could be a prim/prim conversion, where casting is a strict superset.
// Or a boxing conversion, which is always to an exact wrapper class.
return canConvert(src, dst);
} else if (dst.isPrimitive()) {
Wrapper dw = Wrapper.forPrimitiveType(dst);
// Watch out: If src is Number or Object, we could get dynamic narrowing conversion.
// The conversion is known to be widening only if the wrapper type is statically visible.
return (Wrapper.isWrapperType(src) &&
dw.isConvertibleFrom(Wrapper.forWrapperType(src)));
} else {
// R->R always works, but we have to avoid a check-cast to an interface.
return !dst.isInterface() || dst.isAssignableFrom(src);
}
}
private boolean canConvertParameters(Class<?>[] srcTypes, Class<?>[] dstTypes) {
for (int i = 0; i < srcTypes.length; i++) {
if (!canConvert(srcTypes[i], dstTypes[i])) {
......@@ -895,16 +928,6 @@ class MethodType implements java.io.Serializable {
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:
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册