diff --git a/src/share/classes/java/lang/invoke/AdapterMethodHandle.java b/src/share/classes/java/lang/invoke/AdapterMethodHandle.java index b70bce26ed17feb8edc07004e661151a06a74651..8fc33b9879bdd8b5172570475269ab2e0f842cad 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 d0d78895e7773b2b8a741af38ca2e4721a9cbfdb..077101df99aa12a7b7851fc4e074eeb99eeef2ec 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 769289710d98f63397259ec4d620e1631db7112e..31aa02a5a684e0052b8d5690b07f44abf4734807 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 f52c8c06f0a87bb4064e8ff1c4a7a88ededf410f..2c92f9cbe12ee2fbc9678dbee27312e1d9350bc4 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 1e035a46fb1dfc15655e42945872c5da795796d5..b3b63dea28e3b01492f26b31a6687e360b6a7ddb 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 1ab8b344ed9dc30762757f0c15bb8a1742041898..db9aafb3478c59576e901ba1b013ae91b23563da 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 d8c435e86ff221388cd0fd2e4d4e0faae5f7d53f..a3c057dea4b4f5ca09d1965b38c6c5e93884a135 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 3eeeec71ac354ee93acb02b3030b78821e8c0e83..61c4427787425ac0a0b05cc7a66aa8ed1f29855b 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 a0a7b6ae51b682297c174905744c599bf6702d39..5bb14da08531f16bfffb373f76d0a861deb00056 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 02c12c69aad61c037576bbb92e4458dd2e43eff8..b3e1f91f4ac90302cd95f1a3bced9dc26e5358fd 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 6ad4a5a8eead889f155d34e134ebb2ac9c8849b9..817dca788a0166f1248bf7b118bebe48c8b8ee35 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 be1606673815e8cc0e16c3042ac80e02705e0a97..e2d385ee8da4fcdb58d1c781e93da73c20c3e5e5 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 2d46a3910e1c44aea329f7ed6bcd4bc4e9590cb3..e3e6f9d75f17efc36cd4b5f5d24bd6a611c30cb6 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 9ebe37a3b965e075c556f14cb80214c84f27cf29..ded00aec3d6abc42db01b34b58e04e9388930612 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); }