From 988d2756f4746428fe5de27bd5eb59bf3ecd72bb Mon Sep 17 00:00:00 2001 From: jrose Date: Tue, 17 May 2011 19:48:19 -0700 Subject: [PATCH] 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 --- .../java/lang/invoke/AdapterMethodHandle.java | 6 +- .../java/lang/invoke/BoundMethodHandle.java | 2 +- .../java/lang/invoke/FilterGeneric.java | 2 +- .../java/lang/invoke/FilterOneArgument.java | 2 +- .../classes/java/lang/invoke/FromGeneric.java | 2 +- .../java/lang/invoke/MethodHandle.java | 58 ++++++++++++++++--- .../java/lang/invoke/MethodHandleImpl.java | 15 ++--- .../java/lang/invoke/MethodHandleStatics.java | 2 + .../java/lang/invoke/MethodHandles.java | 6 +- .../classes/java/lang/invoke/MethodType.java | 22 +++++-- .../java/lang/invoke/MethodTypeForm.java | 2 + .../java/lang/invoke/SpreadGeneric.java | 4 +- .../classes/java/lang/invoke/ToGeneric.java | 4 +- test/java/lang/invoke/MethodHandlesTest.java | 9 ++- 14 files changed, 98 insertions(+), 38 deletions(-) diff --git a/src/share/classes/java/lang/invoke/AdapterMethodHandle.java b/src/share/classes/java/lang/invoke/AdapterMethodHandle.java index b70bce26e..8fc33b987 100644 --- a/src/share/classes/java/lang/invoke/AdapterMethodHandle.java +++ b/src/share/classes/java/lang/invoke/AdapterMethodHandle.java @@ -546,6 +546,10 @@ class AdapterMethodHandle extends BoundMethodHandle { } 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 @@ class AdapterMethodHandle extends BoundMethodHandle { } @Override - public String toString() { + String debugString() { return getNameString(nonAdapter((MethodHandle)vmtarget), this); } diff --git a/src/share/classes/java/lang/invoke/BoundMethodHandle.java b/src/share/classes/java/lang/invoke/BoundMethodHandle.java index d0d78895e..077101df9 100644 --- a/src/share/classes/java/lang/invoke/BoundMethodHandle.java +++ b/src/share/classes/java/lang/invoke/BoundMethodHandle.java @@ -155,7 +155,7 @@ class BoundMethodHandle extends MethodHandle { } @Override - public String toString() { + String debugString() { return addTypeString(baseName(), this); } diff --git a/src/share/classes/java/lang/invoke/FilterGeneric.java b/src/share/classes/java/lang/invoke/FilterGeneric.java index 769289710..31aa02a5a 100644 --- a/src/share/classes/java/lang/invoke/FilterGeneric.java +++ b/src/share/classes/java/lang/invoke/FilterGeneric.java @@ -234,7 +234,7 @@ class FilterGeneric { protected final MethodHandle target; // ultimate target @Override - public String toString() { + String debugString() { return addTypeString(target, this); } diff --git a/src/share/classes/java/lang/invoke/FilterOneArgument.java b/src/share/classes/java/lang/invoke/FilterOneArgument.java index f52c8c06f..2c92f9cbe 100644 --- a/src/share/classes/java/lang/invoke/FilterOneArgument.java +++ b/src/share/classes/java/lang/invoke/FilterOneArgument.java @@ -41,7 +41,7 @@ class FilterOneArgument extends BoundMethodHandle { protected final MethodHandle target; // Object -> Object @Override - public String toString() { + String debugString() { return target.toString(); } diff --git a/src/share/classes/java/lang/invoke/FromGeneric.java b/src/share/classes/java/lang/invoke/FromGeneric.java index 1e035a46f..b3b63dea2 100644 --- a/src/share/classes/java/lang/invoke/FromGeneric.java +++ b/src/share/classes/java/lang/invoke/FromGeneric.java @@ -260,7 +260,7 @@ class FromGeneric { protected final MethodHandle target; // (any**N) => R @Override - public String toString() { + String debugString() { return addTypeString(target, this); } diff --git a/src/share/classes/java/lang/invoke/MethodHandle.java b/src/share/classes/java/lang/invoke/MethodHandle.java index 1ab8b344e..db9aafb34 100644 --- a/src/share/classes/java/lang/invoke/MethodHandle.java +++ b/src/share/classes/java/lang/invoke/MethodHandle.java @@ -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 @@ public abstract class MethodHandle { * @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> ptypes = new ArrayList>(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 @@ public abstract class MethodHandle { 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 @@ assert(failed); */ 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 @@ assert(failed); */ @Override public String toString() { + if (DEBUG_METHOD_HANDLE_NAMES) return debugString(); + return "MethodHandle"+type; + } + + /*non-public*/ + String debugString() { return getNameString(this); } } diff --git a/src/share/classes/java/lang/invoke/MethodHandleImpl.java b/src/share/classes/java/lang/invoke/MethodHandleImpl.java index d8c435e86..a3c057dea 100644 --- a/src/share/classes/java/lang/invoke/MethodHandleImpl.java +++ b/src/share/classes/java/lang/invoke/MethodHandleImpl.java @@ -163,7 +163,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; } } @Override - public String toString() { + String debugString() { return addTypeString(allocateClass.getSimpleName(), this); } @SuppressWarnings("unchecked") @@ -307,7 +307,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; 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 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; 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 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; } } @Override - public String toString() { + String debugString() { return addTypeString(target, this); } private Object invoke_V(Object... av) throws Throwable { @@ -1081,7 +1082,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; 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 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; static MethodHandle getBootstrap(Class callerClass) { return MethodHandleNatives.getBootstrap(callerClass); } - - static MethodHandle asVarargsCollector(MethodHandle target, Class arrayType) { - return AdapterMethodHandle.makeVarargsCollector(target, arrayType); - } } diff --git a/src/share/classes/java/lang/invoke/MethodHandleStatics.java b/src/share/classes/java/lang/invoke/MethodHandleStatics.java index 3eeeec71a..61c442778 100644 --- a/src/share/classes/java/lang/invoke/MethodHandleStatics.java +++ b/src/share/classes/java/lang/invoke/MethodHandleStatics.java @@ -35,6 +35,8 @@ package java.lang.invoke; 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(); diff --git a/src/share/classes/java/lang/invoke/MethodHandles.java b/src/share/classes/java/lang/invoke/MethodHandles.java index a0a7b6ae5..5bb14da08 100644 --- a/src/share/classes/java/lang/invoke/MethodHandles.java +++ b/src/share/classes/java/lang/invoke/MethodHandles.java @@ -1065,6 +1065,7 @@ return mh1; 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 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2 } return null; } - - /*non-public*/ - static MethodHandle asVarargsCollector(MethodHandle target, Class arrayType) { - return MethodHandleImpl.asVarargsCollector(target, arrayType); - } } diff --git a/src/share/classes/java/lang/invoke/MethodType.java b/src/share/classes/java/lang/invoke/MethodType.java index 02c12c69a..b3e1f91f4 100644 --- a/src/share/classes/java/lang/invoke/MethodType.java +++ b/src/share/classes/java/lang/invoke/MethodType.java @@ -163,7 +163,13 @@ class MethodType implements java.io.Serializable { public static MethodType methodType(Class rtype, List> 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> 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 @@ class MethodType implements java.io.Serializable { */ /*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 @@ class MethodType implements java.io.Serializable { * @throws NullPointerException if {@code ptypesToInsert} or any of its elements is null */ public MethodType insertParameterTypes(int num, List> ptypesToInsert) { - return insertParameterTypes(num, ptypesToInsert.toArray(NO_PTYPES)); + return insertParameterTypes(num, listToArray(ptypesToInsert)); } /** @@ -641,7 +647,8 @@ class MethodType implements java.io.Serializable { } 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 @@ class MethodType implements java.io.Serializable { 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> 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); } diff --git a/src/share/classes/java/lang/invoke/MethodTypeForm.java b/src/share/classes/java/lang/invoke/MethodTypeForm.java index 6ad4a5a8e..817dca788 100644 --- a/src/share/classes/java/lang/invoke/MethodTypeForm.java +++ b/src/share/classes/java/lang/invoke/MethodTypeForm.java @@ -448,6 +448,8 @@ class MethodTypeForm { 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(); diff --git a/src/share/classes/java/lang/invoke/SpreadGeneric.java b/src/share/classes/java/lang/invoke/SpreadGeneric.java index be1606673..e2d385ee8 100644 --- a/src/share/classes/java/lang/invoke/SpreadGeneric.java +++ b/src/share/classes/java/lang/invoke/SpreadGeneric.java @@ -126,7 +126,7 @@ class SpreadGeneric { return spreadGen; } - public String toString() { + String debugString() { return getClass().getSimpleName()+targetType+"["+spreadCount+"]"; } @@ -224,7 +224,7 @@ class SpreadGeneric { protected final MethodHandle target; // (any**N) => R @Override - public String toString() { + String debugString() { return addTypeString(target, this); } diff --git a/src/share/classes/java/lang/invoke/ToGeneric.java b/src/share/classes/java/lang/invoke/ToGeneric.java index 2d46a3910..e3e6f9d75 100644 --- a/src/share/classes/java/lang/invoke/ToGeneric.java +++ b/src/share/classes/java/lang/invoke/ToGeneric.java @@ -258,7 +258,7 @@ class ToGeneric { return toGen; } - public String toString() { + String debugString() { return "ToGeneric"+entryType +(primsAtEndOrder!=null?"[reorder]":""); } @@ -340,7 +340,7 @@ class ToGeneric { protected final MethodHandle convert; // Object -> R @Override - public String toString() { + String debugString() { return target == null ? "prototype:"+convert : addTypeString(target, this); } diff --git a/test/java/lang/invoke/MethodHandlesTest.java b/test/java/lang/invoke/MethodHandlesTest.java index 9ebe37a3b..ded00aec3 100644 --- a/test/java/lang/invoke/MethodHandlesTest.java +++ b/test/java/lang/invoke/MethodHandlesTest.java @@ -505,8 +505,15 @@ public class MethodHandlesTest { 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); } -- GitLab