7044892: JSR 292: API entry points sometimes throw the wrong exceptions or doesn't throw the expected one
Summary: point-fixes for 7038847, 7038860, 7042656, 7042829, 7041853, and several other reports
Reviewed-by: never, kvn
--- a/jdk/src/share/classes/java/lang/invoke/AdapterMethodHandle.java Tue May 17 19:48:14 2011 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/AdapterMethodHandle.java Tue May 17 19:48:19 2011 -0700
@@ -546,6 +546,10 @@
}
static MethodHandle makeVarargsCollector(MethodHandle target, Class<?> arrayType) {
+ MethodType type = target.type();
+ int last = type.parameterCount() - 1;
+ if (type.parameterType(last) != arrayType)
+ target = target.asType(type.changeParameterType(last, arrayType));
return new AsVarargsCollector(target, arrayType);
}
@@ -1144,7 +1148,7 @@
}
@Override
- public String toString() {
+ String debugString() {
return getNameString(nonAdapter((MethodHandle)vmtarget), this);
}
--- a/jdk/src/share/classes/java/lang/invoke/BoundMethodHandle.java Tue May 17 19:48:14 2011 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/BoundMethodHandle.java Tue May 17 19:48:19 2011 -0700
@@ -155,7 +155,7 @@
}
@Override
- public String toString() {
+ String debugString() {
return addTypeString(baseName(), this);
}
--- a/jdk/src/share/classes/java/lang/invoke/FilterGeneric.java Tue May 17 19:48:14 2011 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/FilterGeneric.java Tue May 17 19:48:19 2011 -0700
@@ -234,7 +234,7 @@
protected final MethodHandle target; // ultimate target
@Override
- public String toString() {
+ String debugString() {
return addTypeString(target, this);
}
--- a/jdk/src/share/classes/java/lang/invoke/FilterOneArgument.java Tue May 17 19:48:14 2011 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/FilterOneArgument.java Tue May 17 19:48:19 2011 -0700
@@ -41,7 +41,7 @@
protected final MethodHandle target; // Object -> Object
@Override
- public String toString() {
+ String debugString() {
return target.toString();
}
--- a/jdk/src/share/classes/java/lang/invoke/FromGeneric.java Tue May 17 19:48:14 2011 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/FromGeneric.java Tue May 17 19:48:19 2011 -0700
@@ -260,7 +260,7 @@
protected final MethodHandle target; // (any**N) => R
@Override
- public String toString() {
+ String debugString() {
return addTypeString(target, this);
}
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandle.java Tue May 17 19:48:14 2011 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandle.java Tue May 17 19:48:19 2011 -0700
@@ -26,6 +26,7 @@
package java.lang.invoke;
+import java.util.ArrayList;
import sun.invoke.util.ValueConversions;
import static java.lang.invoke.MethodHandleStatics.*;
@@ -750,11 +751,46 @@
* @see #asCollector
*/
public MethodHandle asSpreader(Class<?> arrayType, int arrayLength) {
- Class<?> arrayElement = arrayType.getComponentType();
- if (arrayElement == null) throw newIllegalArgumentException("not an array type");
+ asSpreaderChecks(arrayType, arrayLength);
+ return MethodHandleImpl.spreadArguments(this, arrayType, arrayLength);
+ }
+
+ private void asSpreaderChecks(Class<?> arrayType, int arrayLength) {
+ spreadArrayChecks(arrayType, arrayLength);
int nargs = type().parameterCount();
if (nargs < arrayLength) throw newIllegalArgumentException("bad spread array length");
- return MethodHandleImpl.spreadArguments(this, arrayType, arrayLength);
+ if (arrayType != Object[].class && arrayLength != 0) {
+ boolean sawProblem = false;
+ Class<?> arrayElement = arrayType.getComponentType();
+ for (int i = nargs - arrayLength; i < nargs; i++) {
+ if (!MethodType.canConvert(arrayElement, type().parameterType(i))) {
+ sawProblem = true;
+ break;
+ }
+ }
+ if (sawProblem) {
+ ArrayList<Class<?>> ptypes = new ArrayList<Class<?>>(type().parameterList());
+ for (int i = nargs - arrayLength; i < nargs; i++) {
+ ptypes.set(i, arrayElement);
+ }
+ // elicit an error:
+ this.asType(MethodType.methodType(type().returnType(), ptypes));
+ }
+ }
+ }
+
+ private void spreadArrayChecks(Class<?> arrayType, int arrayLength) {
+ Class<?> arrayElement = arrayType.getComponentType();
+ if (arrayElement == null)
+ throw newIllegalArgumentException("not an array type", arrayType);
+ if ((arrayLength & 0x7F) != arrayLength) {
+ if ((arrayLength & 0xFF) != arrayLength)
+ throw newIllegalArgumentException("array length is not legal", arrayLength);
+ assert(arrayLength >= 128);
+ if (arrayElement == long.class ||
+ arrayElement == double.class)
+ throw newIllegalArgumentException("array length is not legal for long[] or double[]", arrayLength);
+ }
}
/**
@@ -802,10 +838,8 @@
return MethodHandleImpl.collectArguments(this, type.parameterCount()-1, collector);
}
- private void asCollectorChecks(Class<?> arrayType, int arrayLength) {
- Class<?> arrayElement = arrayType.getComponentType();
- if (arrayElement == null)
- throw newIllegalArgumentException("not an array type", arrayType);
+ private void asCollectorChecks(Class<?> arrayType, int arrayLength) {
+ spreadArrayChecks(arrayType, arrayLength);
int nargs = type().parameterCount();
if (nargs == 0 || !type().parameterType(nargs-1).isAssignableFrom(arrayType))
throw newIllegalArgumentException("array type not assignable to trailing argument", this, arrayType);
@@ -965,8 +999,8 @@
*/
public MethodHandle asVarargsCollector(Class<?> arrayType) {
Class<?> arrayElement = arrayType.getComponentType();
- if (arrayElement == null) throw newIllegalArgumentException("not an array type");
- return MethodHandles.asVarargsCollector(this, arrayType);
+ asCollectorChecks(arrayType, 0);
+ return AdapterMethodHandle.makeVarargsCollector(this, arrayType);
}
/**
@@ -1043,6 +1077,12 @@
*/
@Override
public String toString() {
+ if (DEBUG_METHOD_HANDLE_NAMES) return debugString();
+ return "MethodHandle"+type;
+ }
+
+ /*non-public*/
+ String debugString() {
return getNameString(this);
}
}
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java Tue May 17 19:48:14 2011 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java Tue May 17 19:48:19 2011 -0700
@@ -163,7 +163,7 @@
}
}
@Override
- public String toString() {
+ String debugString() {
return addTypeString(allocateClass.getSimpleName(), this);
}
@SuppressWarnings("unchecked")
@@ -307,7 +307,7 @@
this.base = staticBase(field);
}
@Override
- public String toString() { return addTypeString(name, this); }
+ String debugString() { return addTypeString(name, this); }
int getFieldI(C obj) { return unsafe.getInt(obj, offset); }
void setFieldI(C obj, int x) { unsafe.putInt(obj, offset, x); }
@@ -338,8 +338,9 @@
try {
// FIXME: Should not have to create 'f' to get this value.
f = c.getDeclaredField(field.getName());
+ // Note: Previous line might invalidly throw SecurityException (7042829)
return unsafe.staticFieldBase(f);
- } catch (Exception ee) {
+ } catch (NoSuchFieldException ee) {
throw uncaughtException(ee);
}
}
@@ -936,7 +937,7 @@
}
}
@Override
- public String toString() {
+ String debugString() {
return addTypeString(target, this);
}
private Object invoke_V(Object... av) throws Throwable {
@@ -1081,7 +1082,7 @@
this.catcher = catcher;
}
@Override
- public String toString() {
+ String debugString() {
return addTypeString(target, this);
}
private Object invoke_V(Object... av) throws Throwable {
@@ -1248,8 +1249,4 @@
static MethodHandle getBootstrap(Class<?> callerClass) {
return MethodHandleNatives.getBootstrap(callerClass);
}
-
- static MethodHandle asVarargsCollector(MethodHandle target, Class<?> arrayType) {
- return AdapterMethodHandle.makeVarargsCollector(target, arrayType);
- }
}
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandleStatics.java Tue May 17 19:48:14 2011 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleStatics.java Tue May 17 19:48:19 2011 -0700
@@ -35,6 +35,8 @@
private MethodHandleStatics() { } // do not instantiate
+ static final boolean DEBUG_METHOD_HANDLE_NAMES = Boolean.getBoolean("java.lang.invoke.MethodHandle.DEBUG_NAMES");
+
/*non-public*/ static String getNameString(MethodHandle target, MethodType type) {
if (type == null)
type = target.type();
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandles.java Tue May 17 19:48:14 2011 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandles.java Tue May 17 19:48:19 2011 -0700
@@ -1065,6 +1065,7 @@
if (!method.isProtected() || method.isStatic()
|| allowedModes == TRUSTED
|| method.getDeclaringClass() == lookupClass()
+ || VerifyAccess.isSamePackage(method.getDeclaringClass(), lookupClass())
|| (ALLOW_NESTMATE_ACCESS &&
VerifyAccess.isSamePackageMember(method.getDeclaringClass(), lookupClass())))
return mh;
@@ -2383,9 +2384,4 @@
}
return null;
}
-
- /*non-public*/
- static MethodHandle asVarargsCollector(MethodHandle target, Class<?> arrayType) {
- return MethodHandleImpl.asVarargsCollector(target, arrayType);
- }
}
--- a/jdk/src/share/classes/java/lang/invoke/MethodType.java Tue May 17 19:48:14 2011 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/MethodType.java Tue May 17 19:48:19 2011 -0700
@@ -163,7 +163,13 @@
public static
MethodType methodType(Class<?> rtype, List<Class<?>> ptypes) {
boolean notrust = false; // random List impl. could return evil ptypes array
- return makeImpl(rtype, ptypes.toArray(NO_PTYPES), notrust);
+ return makeImpl(rtype, listToArray(ptypes), notrust);
+ }
+
+ private static Class<?>[] listToArray(List<Class<?>> ptypes) {
+ // sanity check the size before the toArray call, since size might be huge
+ checkSlotCount(ptypes.size());
+ return ptypes.toArray(NO_PTYPES);
}
/**
@@ -228,7 +234,7 @@
*/
/*trusted*/ static
MethodType makeImpl(Class<?> rtype, Class<?>[] ptypes, boolean trusted) {
- if (ptypes == null || ptypes.length == 0) {
+ if (ptypes.length == 0) {
ptypes = NO_PTYPES; trusted = true;
}
MethodType mt1 = new MethodType(rtype, ptypes);
@@ -372,7 +378,7 @@
* @throws NullPointerException if {@code ptypesToInsert} or any of its elements is null
*/
public MethodType insertParameterTypes(int num, List<Class<?>> ptypesToInsert) {
- return insertParameterTypes(num, ptypesToInsert.toArray(NO_PTYPES));
+ return insertParameterTypes(num, listToArray(ptypesToInsert));
}
/**
@@ -641,7 +647,8 @@
}
return true;
}
- private static boolean canConvert(Class<?> src, Class<?> dst) {
+ /*non-public*/
+ static boolean canConvert(Class<?> src, Class<?> dst) {
if (src == dst || dst == void.class) return true;
if (src.isPrimitive() && dst.isPrimitive()) {
if (!Wrapper.forPrimitiveType(dst)
@@ -739,9 +746,14 @@
public static MethodType fromMethodDescriptorString(String descriptor, ClassLoader loader)
throws IllegalArgumentException, TypeNotPresentException
{
+ if (!descriptor.startsWith("(") || // also generates NPE if needed
+ descriptor.indexOf(')') < 0 ||
+ descriptor.indexOf('.') >= 0)
+ throw new IllegalArgumentException("not a method descriptor: "+descriptor);
List<Class<?>> types = BytecodeDescriptor.parseMethod(descriptor, loader);
Class<?> rtype = types.remove(types.size() - 1);
- Class<?>[] ptypes = types.toArray(NO_PTYPES);
+ checkSlotCount(types.size());
+ Class<?>[] ptypes = listToArray(types);
return makeImpl(rtype, ptypes, true);
}
--- a/jdk/src/share/classes/java/lang/invoke/MethodTypeForm.java Tue May 17 19:48:14 2011 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/MethodTypeForm.java Tue May 17 19:48:19 2011 -0700
@@ -448,6 +448,8 @@
Class<?>[] cs = null;
for (int imax = ts.length, i = 0; i < imax; i++) {
Class<?> c = canonicalize(ts[i], how);
+ if (c == void.class)
+ c = null; // a Void parameter was unwrapped to void; ignore
if (c != null) {
if (cs == null)
cs = ts.clone();
--- a/jdk/src/share/classes/java/lang/invoke/SpreadGeneric.java Tue May 17 19:48:14 2011 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/SpreadGeneric.java Tue May 17 19:48:19 2011 -0700
@@ -126,7 +126,7 @@
return spreadGen;
}
- public String toString() {
+ String debugString() {
return getClass().getSimpleName()+targetType+"["+spreadCount+"]";
}
@@ -224,7 +224,7 @@
protected final MethodHandle target; // (any**N) => R
@Override
- public String toString() {
+ String debugString() {
return addTypeString(target, this);
}
--- a/jdk/src/share/classes/java/lang/invoke/ToGeneric.java Tue May 17 19:48:14 2011 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/ToGeneric.java Tue May 17 19:48:19 2011 -0700
@@ -258,7 +258,7 @@
return toGen;
}
- public String toString() {
+ String debugString() {
return "ToGeneric"+entryType
+(primsAtEndOrder!=null?"[reorder]":"");
}
@@ -340,7 +340,7 @@
protected final MethodHandle convert; // Object -> R
@Override
- public String toString() {
+ String debugString() {
return target == null ? "prototype:"+convert : addTypeString(target, this);
}
--- a/jdk/test/java/lang/invoke/MethodHandlesTest.java Tue May 17 19:48:14 2011 -0700
+++ b/jdk/test/java/lang/invoke/MethodHandlesTest.java Tue May 17 19:48:19 2011 -0700
@@ -505,8 +505,15 @@
System.out.print(':');
}
+ static final boolean DEBUG_METHOD_HANDLE_NAMES = Boolean.getBoolean("java.lang.invoke.MethodHandle.DEBUG_NAMES");
+
// rough check of name string
- static void assertNameStringContains(Object x, String s) {
+ static void assertNameStringContains(MethodHandle x, String s) {
+ if (!DEBUG_METHOD_HANDLE_NAMES) {
+ // ignore s
+ assertEquals("MethodHandle"+x.type(), x.toString());
+ return;
+ }
if (x.toString().contains(s)) return;
assertEquals(s, x);
}