提交 a605690a 编写于 作者: V vlivanov

8060483: NPE with explicitCastArguments unboxing null

Reviewed-by: attila, lagergren
上级 7cf9e602
...@@ -891,11 +891,6 @@ class MethodType implements java.io.Serializable { ...@@ -891,11 +891,6 @@ class MethodType implements java.io.Serializable {
* with MHs.eCE. * with MHs.eCE.
* 3a. unboxing conversions can be followed by the full matrix of primitive conversions * 3a. unboxing conversions can be followed by the full matrix of primitive conversions
* 3b. unboxing of null is permitted (creates a zero primitive value) * 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. * Other than interfaces, reference-to-reference conversions are the same.
* Boxing primitives to references is the same for both operators. * Boxing primitives to references is the same for both operators.
*/ */
...@@ -906,11 +901,8 @@ class MethodType implements java.io.Serializable { ...@@ -906,11 +901,8 @@ class MethodType implements java.io.Serializable {
// Or a boxing conversion, which is always to an exact wrapper class. // Or a boxing conversion, which is always to an exact wrapper class.
return canConvert(src, dst); return canConvert(src, dst);
} else if (dst.isPrimitive()) { } else if (dst.isPrimitive()) {
Wrapper dw = Wrapper.forPrimitiveType(dst); // Unboxing behavior is different between MHs.eCA & MH.asType (see 3b).
// Watch out: If src is Number or Object, we could get dynamic narrowing conversion. return false;
// 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 { } else {
// R->R always works, but we have to avoid a check-cast to an interface. // R->R always works, but we have to avoid a check-cast to an interface.
return !dst.isInterface() || dst.isAssignableFrom(src); return !dst.isInterface() || dst.isAssignableFrom(src);
......
...@@ -26,19 +26,19 @@ ...@@ -26,19 +26,19 @@
package sun.invoke.util; package sun.invoke.util;
public enum Wrapper { public enum Wrapper {
BOOLEAN(Boolean.class, boolean.class, 'Z', (Boolean)false, new boolean[0], Format.unsigned(1)), // wrapperType primitiveType char zero emptyArray format
BOOLEAN( Boolean.class, boolean.class, 'Z', (Boolean)false, new boolean[0], Format.unsigned( 1)),
// These must be in the order defined for widening primitive conversions in JLS 5.1.2 // These must be in the order defined for widening primitive conversions in JLS 5.1.2
BYTE(Byte.class, byte.class, 'B', (Byte)(byte)0, new byte[0], Format.signed(8)), BYTE ( Byte.class, byte.class, 'B', (Byte)(byte)0, new byte[0], Format.signed( 8)),
SHORT(Short.class, short.class, 'S', (Short)(short)0, new short[0], Format.signed(16)), SHORT ( Short.class, short.class, 'S', (Short)(short)0, new short[0], Format.signed( 16)),
CHAR(Character.class, char.class, 'C', (Character)(char)0, new char[0], Format.unsigned(16)), CHAR (Character.class, char.class, 'C', (Character)(char)0, new char[0], Format.unsigned(16)),
INT(Integer.class, int.class, 'I', (Integer)/*(int)*/0, new int[0], Format.signed(32)), INT ( Integer.class, int.class, 'I', (Integer)/*(int)*/0, new int[0], Format.signed( 32)),
LONG(Long.class, long.class, 'J', (Long)(long)0, new long[0], Format.signed(64)), LONG ( Long.class, long.class, 'J', (Long)(long)0, new long[0], Format.signed( 64)),
FLOAT(Float.class, float.class, 'F', (Float)(float)0, new float[0], Format.floating(32)), FLOAT ( Float.class, float.class, 'F', (Float)(float)0, new float[0], Format.floating(32)),
DOUBLE(Double.class, double.class, 'D', (Double)(double)0, new double[0], Format.floating(64)), DOUBLE ( Double.class, double.class, 'D', (Double)(double)0, new double[0], Format.floating(64)),
//NULL(Null.class, null.class, 'N', null, null, Format.other(1)), OBJECT ( Object.class, Object.class, 'L', null, new Object[0], Format.other( 1)),
OBJECT(Object.class, Object.class, 'L', null, new Object[0], Format.other(1)),
// VOID must be the last type, since it is "assignable" from any other type: // VOID must be the last type, since it is "assignable" from any other type:
VOID(Void.class, void.class, 'V', null, null, Format.other(0)), VOID ( Void.class, void.class, 'V', null, null, Format.other( 0)),
; ;
private final Class<?> wrapperType; private final Class<?> wrapperType;
......
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.lang.invoke;
import sun.invoke.util.Wrapper;
/* @test
* @summary unit tests for MethodHandles.explicitCastArguments()
*
* @run main/bootclasspath java.lang.invoke.ExplicitCastArgumentsTest
*/
public class ExplicitCastArgumentsTest {
private static final boolean VERBOSE = Boolean.getBoolean("verbose");
public static void main(String[] args) throws Throwable {
for (Wrapper from : Wrapper.values()) {
for (Wrapper to : Wrapper.values()) {
if (from == Wrapper.VOID || to == Wrapper.VOID) continue;
testRef2Prim (from, to);
}
}
System.out.println("TEST PASSED");
}
public static void testRef2Prim(Wrapper from, Wrapper to) throws Throwable {
// MHs.eCA javadoc:
// If T0 is a reference and T1 a primitive, and if the reference is null at runtime, a zero value is introduced.
test(from.wrapperType(), to.primitiveType(), null, false);
}
public static void test(Class<?> from, Class<?> to, Object param, boolean failureExpected) throws Throwable {
if (VERBOSE) System.out.printf("%-10s => %-10s: %5s: ", from.getSimpleName(), to.getSimpleName(), param);
MethodHandle original = MethodHandles.identity(from);
MethodType newType = original.type().changeReturnType(to);
try {
MethodHandle target = MethodHandles.explicitCastArguments(original, newType);
Object result = target.invokeWithArguments(param);
if (VERBOSE) {
String resultStr;
if (result != null) {
resultStr = String.format("%10s (%10s)", "'"+result+"'", result.getClass().getSimpleName());
} else {
resultStr = String.format("%10s", result);
}
System.out.println(resultStr);
}
if (failureExpected) {
String msg = String.format("No exception thrown: %s => %s; parameter: %s", from, to, param);
throw new AssertionError(msg);
}
} catch (AssertionError e) {
throw e; // report test failure
} catch (Throwable e) {
if (VERBOSE) System.out.printf("%s: %s\n", e.getClass(), e.getMessage());
if (!failureExpected) {
String msg = String.format("Unexpected exception was thrown: %s => %s; parameter: %s", from, to, param);
throw new AssertionError(msg, e);
}
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册