changeset 4247:127560d6f6e6

Merge
author trims
date Tue, 24 May 2011 14:11:38 -0700
parents 5f69702cf570 be4b9e596352
children 23bdcede4e39 bc97b962330e
files
diffstat 18 files changed, 259 insertions(+), 87 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/java/lang/invoke/AdapterMethodHandle.java	Fri May 20 16:04:09 2011 -0700
+++ b/src/share/classes/java/lang/invoke/AdapterMethodHandle.java	Tue May 24 14:11:38 2011 -0700
@@ -141,7 +141,7 @@
         while (lastConv >= 0) {
             Class<?> src = newType.parameterType(lastConv); // source type
             Class<?> dst = oldType.parameterType(lastConv); // destination type
-            if (VerifyType.isNullConversion(src, dst)) {
+            if (isTrivialConversion(src, dst, level)) {
                 --lastConv;
             } else {
                 break;
@@ -150,7 +150,7 @@
 
         Class<?> needReturn = newType.returnType();
         Class<?> haveReturn = oldType.returnType();
-        boolean retConv = !VerifyType.isNullConversion(haveReturn, needReturn);
+        boolean retConv = !isTrivialConversion(haveReturn, needReturn, level);
 
         // Now build a chain of one or more adapters.
         MethodHandle adapter = target, adapter2;
@@ -158,7 +158,7 @@
         for (int i = 0; i <= lastConv; i++) {
             Class<?> src = newType.parameterType(i); // source type
             Class<?> dst = midType.parameterType(i); // destination type
-            if (VerifyType.isNullConversion(src, dst)) {
+            if (isTrivialConversion(src, dst, level)) {
                 // do nothing: difference is trivial
                 continue;
             }
@@ -219,6 +219,22 @@
         return adapter;
     }
 
+    private static boolean isTrivialConversion(Class<?> src, Class<?> dst, int level) {
+        if (src == dst || dst == void.class)  return true;
+        if (!VerifyType.isNullConversion(src, dst))  return false;
+        if (level > 1)  return true;  // explicitCastArguments
+        boolean sp = src.isPrimitive();
+        boolean dp = dst.isPrimitive();
+        if (sp != dp)  return false;
+        if (sp) {
+            // in addition to being a null conversion, forbid boolean->int etc.
+            return Wrapper.forPrimitiveType(dst)
+                    .isConvertibleFrom(Wrapper.forPrimitiveType(src));
+        } else {
+            return dst.isAssignableFrom(src);
+        }
+    }
+
     private static MethodHandle makeReturnConversion(MethodHandle target, Class<?> haveReturn, Class<?> needReturn) {
         MethodHandle adjustReturn;
         if (haveReturn == void.class) {
@@ -530,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);
     }
 
@@ -596,7 +616,7 @@
                 || !VerifyType.isNullConversion(castType, dst))
             return false;
         int diff = diffTypes(newType, targetType, false);
-        return (diff == arg+1);  // arg is sole non-trivial diff
+        return (diff == arg+1) || (diff == 0);  // arg is sole non-trivial diff
     }
     /** Can an primitive conversion adapter validly convert src to dst? */
     static boolean canCheckCast(Class<?> src, Class<?> dst) {
@@ -1033,8 +1053,9 @@
                 Class<?> spreadArgType, int spreadArgPos, int spreadArgCount) {
         // FIXME: Get rid of newType; derive new arguments from structure of spreadArgType
         MethodType targetType = target.type();
-        if (!canSpreadArguments(newType, targetType, spreadArgType, spreadArgPos, spreadArgCount))
-            return null;
+        assert(canSpreadArguments(newType, targetType, spreadArgType, spreadArgPos, spreadArgCount))
+            : "[newType, targetType, spreadArgType, spreadArgPos, spreadArgCount] = "
+              + Arrays.asList(newType, targetType, spreadArgType, spreadArgPos, spreadArgCount);
         // dest is not significant; remove?
         int dest = T_VOID;
         for (int i = 0; i < spreadArgCount; i++) {
@@ -1127,7 +1148,7 @@
     }
 
     @Override
-    public String toString() {
+    String debugString() {
         return getNameString(nonAdapter((MethodHandle)vmtarget), this);
     }
 
--- a/src/share/classes/java/lang/invoke/BoundMethodHandle.java	Fri May 20 16:04:09 2011 -0700
+++ b/src/share/classes/java/lang/invoke/BoundMethodHandle.java	Tue May 24 14:11:38 2011 -0700
@@ -155,7 +155,7 @@
     }
 
     @Override
-    public String toString() {
+    String debugString() {
         return addTypeString(baseName(), this);
     }
 
--- a/src/share/classes/java/lang/invoke/FilterGeneric.java	Fri May 20 16:04:09 2011 -0700
+++ b/src/share/classes/java/lang/invoke/FilterGeneric.java	Tue May 24 14:11:38 2011 -0700
@@ -234,7 +234,7 @@
         protected final MethodHandle target; // ultimate target
 
         @Override
-        public String toString() {
+        String debugString() {
             return addTypeString(target, this);
         }
 
--- a/src/share/classes/java/lang/invoke/FilterOneArgument.java	Fri May 20 16:04:09 2011 -0700
+++ b/src/share/classes/java/lang/invoke/FilterOneArgument.java	Tue May 24 14:11:38 2011 -0700
@@ -41,7 +41,7 @@
     protected final MethodHandle target;  // Object -> Object
 
     @Override
-    public String toString() {
+    String debugString() {
         return target.toString();
     }
 
--- a/src/share/classes/java/lang/invoke/FromGeneric.java	Fri May 20 16:04:09 2011 -0700
+++ b/src/share/classes/java/lang/invoke/FromGeneric.java	Tue May 24 14:11:38 2011 -0700
@@ -260,7 +260,7 @@
         protected final MethodHandle target;   // (any**N) => R
 
         @Override
-        public String toString() {
+        String debugString() {
             return addTypeString(target, this);
         }
 
--- a/src/share/classes/java/lang/invoke/InvokeGeneric.java	Fri May 20 16:04:09 2011 -0700
+++ b/src/share/classes/java/lang/invoke/InvokeGeneric.java	Tue May 24 14:11:38 2011 -0700
@@ -129,20 +129,17 @@
         if (needType == erasedCallerType.returnType())
             return false;  // no conversions possible, since must be primitive or Object
         Class<?> haveType = target.type().returnType();
-        if (VerifyType.isNullConversion(haveType, needType))
+        if (VerifyType.isNullConversion(haveType, needType) && !needType.isInterface())
             return false;
         return true;
     }
-    private MethodHandle addReturnConversion(MethodHandle target, Class<?> type) {
-        if (true) throw new RuntimeException("NYI");
+    private MethodHandle addReturnConversion(MethodHandle finisher, Class<?> type) {
         // FIXME: This is slow because it creates a closure node on every call that requires a return cast.
-        MethodType targetType = target.type();
+        MethodType finisherType = finisher.type();
         MethodHandle caster = ValueConversions.identity(type);
-        caster = caster.asType(MethodType.methodType(type, targetType.returnType()));
-        // Drop irrelevant arguments, because we only care about the return value:
-        caster = MethodHandles.dropArguments(caster, 1, targetType.parameterList());
-        MethodHandle result = MethodHandles.foldArguments(caster, target);
-        return result.asType(target.type());
+        caster = caster.asType(caster.type().changeParameterType(0, finisherType.returnType()));
+        finisher = MethodHandles.filterReturnValue(finisher, caster);
+        return finisher.asType(finisherType);
     }
 
     public String toString() {
--- a/src/share/classes/java/lang/invoke/MethodHandle.java	Fri May 20 16:04:09 2011 -0700
+++ b/src/share/classes/java/lang/invoke/MethodHandle.java	Tue May 24 14:11:38 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.*;
 
@@ -708,9 +709,9 @@
      */
     public MethodHandle asType(MethodType newType) {
         if (!type.isConvertibleTo(newType)) {
-            throw new WrongMethodTypeException("cannot convert "+type+" to "+newType);
+            throw new WrongMethodTypeException("cannot convert "+this+" to "+newType);
         }
-        return MethodHandles.convertArguments(this, newType);
+        return MethodHandleImpl.convertArguments(this, newType, 1);
     }
 
     /**
@@ -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/src/share/classes/java/lang/invoke/MethodHandleImpl.java	Fri May 20 16:04:09 2011 -0700
+++ b/src/share/classes/java/lang/invoke/MethodHandleImpl.java	Tue May 24 14:11:38 2011 -0700
@@ -93,9 +93,28 @@
     static
     MethodHandle makeAllocator(MethodHandle rawConstructor) {
         MethodType rawConType = rawConstructor.type();
+        Class<?> allocateClass = rawConType.parameterType(0);
         // Wrap the raw (unsafe) constructor with the allocation of a suitable object.
+        if (AdapterMethodHandle.canCollectArguments(rawConType, MethodType.methodType(allocateClass), 0, true)) {
+            // allocator(arg...)
+            // [fold]=> cookedConstructor(obj=allocate(C), arg...)
+            // [dup,collect]=> identity(obj, void=rawConstructor(obj, arg...))
+            MethodHandle returner = MethodHandles.identity(allocateClass);
+            MethodType ctype = rawConType.insertParameterTypes(0, allocateClass).changeReturnType(allocateClass);
+            MethodHandle  cookedConstructor = AdapterMethodHandle.makeCollectArguments(returner, rawConstructor, 1, false);
+            assert(cookedConstructor.type().equals(ctype));
+            ctype = ctype.dropParameterTypes(0, 1);
+            cookedConstructor = AdapterMethodHandle.makeCollectArguments(cookedConstructor, returner, 0, true);
+            MethodHandle allocator = new AllocateObject(allocateClass);
+            // allocate() => new C(void)
+            assert(allocator.type().equals(MethodType.methodType(allocateClass)));
+            ctype = ctype.dropParameterTypes(0, 1);
+            MethodHandle fold = foldArguments(cookedConstructor, ctype, 0, allocator);
+            return fold;
+        }
+        assert(MethodHandleNatives.workaroundWithoutRicochetFrames());  // this code is deprecated
         MethodHandle allocator
-            = AllocateObject.make(rawConType.parameterType(0), rawConstructor);
+            = AllocateObject.make(allocateClass, rawConstructor);
         assert(allocator.type()
                .equals(rawConType.dropParameterTypes(0, 1).changeReturnType(rawConType.parameterType(0))));
         return allocator;
@@ -112,8 +131,16 @@
             super(invoker);
             this.allocateClass = allocateClass;
             this.rawConstructor = rawConstructor;
+            assert(MethodHandleNatives.workaroundWithoutRicochetFrames());  // this code is deprecated
+        }
+        // for allocation only:
+        private AllocateObject(Class<C> allocateClass) {
+            super(ALLOCATE.asType(MethodType.methodType(allocateClass, AllocateObject.class)));
+            this.allocateClass = allocateClass;
+            this.rawConstructor = null;
         }
         static MethodHandle make(Class<?> allocateClass, MethodHandle rawConstructor) {
+            assert(MethodHandleNatives.workaroundWithoutRicochetFrames());  // this code is deprecated
             MethodType rawConType = rawConstructor.type();
             assert(rawConType.parameterType(0) == allocateClass);
             MethodType newType = rawConType.dropParameterTypes(0, 1).changeReturnType(allocateClass);
@@ -129,14 +156,14 @@
             } else {
                 MethodHandle invoke = VARARGS_INVOKE;
                 MethodType conType = CON_TYPES[nargs];
-                MethodHandle gcon = spreadArguments(rawConstructor, conType, 1);
+                MethodHandle gcon = spreadArgumentsFromPos(rawConstructor, conType, 1);
                 if (gcon == null)  return null;
                 MethodHandle galloc = new AllocateObject(invoke, allocateClass, gcon);
                 return collectArguments(galloc, newType, 1, null);
             }
         }
         @Override
-        public String toString() {
+        String debugString() {
             return addTypeString(allocateClass.getSimpleName(), this);
         }
         @SuppressWarnings("unchecked")
@@ -214,9 +241,11 @@
         // For testing use this:
         //static final MethodHandle[] INVOKES = Arrays.copyOf(makeInvokes(), 2);
         static final MethodHandle VARARGS_INVOKE;
+        static final MethodHandle ALLOCATE;
         static {
             try {
                 VARARGS_INVOKE = IMPL_LOOKUP.findVirtual(AllocateObject.class, "invoke_V", MethodType.genericMethodType(0, true));
+                ALLOCATE = IMPL_LOOKUP.findVirtual(AllocateObject.class, "allocate", MethodType.genericMethodType(0));
             } catch (ReflectiveOperationException ex) {
                 throw uncaughtException(ex);
             }
@@ -278,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); }
@@ -309,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);
             }
         }
@@ -747,7 +777,7 @@
                 .insertParameterTypes(keepPosArgs, arrayType);
         return spreadArguments(target, newType, keepPosArgs, arrayType, arrayLength);
     }
-    static MethodHandle spreadArguments(MethodHandle target, MethodType newType, int spreadArgPos) {
+    static MethodHandle spreadArgumentsFromPos(MethodHandle target, MethodType newType, int spreadArgPos) {
         int arrayLength = target.type().parameterCount() - spreadArgPos;
         return spreadArguments(target, newType, spreadArgPos, Object[].class, arrayLength);
     }
@@ -761,9 +791,7 @@
         // spread the last argument of newType to oldType
         assert(arrayLength == oldType.parameterCount() - spreadArgPos);
         assert(newType.parameterType(spreadArgPos) == arrayType);
-        MethodHandle res = AdapterMethodHandle.makeSpreadArguments(newType, target, arrayType, spreadArgPos, arrayLength);
-        if (res == null)  throw new IllegalArgumentException("spread on "+target+" with "+arrayType.getSimpleName());
-        return res;
+        return AdapterMethodHandle.makeSpreadArguments(newType, target, arrayType, spreadArgPos, arrayLength);
     }
 
     static MethodHandle collectArguments(MethodHandle target,
@@ -771,6 +799,7 @@
                                                 MethodHandle collector) {
         MethodType type = target.type();
         Class<?> collectType = collector.type().returnType();
+        assert(collectType != void.class);  // else use foldArguments
         if (collectType != type.parameterType(collectArg))
             target = target.asType(type.changeParameterType(collectArg, collectType));
         MethodType newType = type
@@ -878,9 +907,11 @@
             this.test = test;
             this.target = target;
             this.fallback = fallback;
+            assert(MethodHandleNatives.workaroundWithoutRicochetFrames());  // this code is deprecated
         }
         // FIXME: Build the control flow out of foldArguments.
         static MethodHandle make(MethodHandle test, MethodHandle target, MethodHandle fallback) {
+            assert(MethodHandleNatives.workaroundWithoutRicochetFrames());  // this code is deprecated
             MethodType type = target.type();
             int nargs = type.parameterCount();
             if (nargs < INVOKES.length) {
@@ -897,16 +928,16 @@
                 MethodHandle invoke = VARARGS_INVOKE;
                 MethodType gtype = MethodType.genericMethodType(1);
                 assert(invoke.type().dropParameterTypes(0,1) == gtype);
-                MethodHandle gtest = spreadArguments(test, gtype.changeReturnType(boolean.class), 0);
-                MethodHandle gtarget = spreadArguments(target, gtype, 0);
-                MethodHandle gfallback = spreadArguments(fallback, gtype, 0);
+                MethodHandle gtest = spreadArgumentsFromPos(test, gtype.changeReturnType(boolean.class), 0);
+                MethodHandle gtarget = spreadArgumentsFromPos(target, gtype, 0);
+                MethodHandle gfallback = spreadArgumentsFromPos(fallback, gtype, 0);
                 MethodHandle gguard = new GuardWithTest(invoke, gtest, gtarget, gfallback);
                 if (gtest == null || gtarget == null || gfallback == null)  return null;
                 return collectArguments(gguard, type, 0, null);
             }
         }
         @Override
-        public String toString() {
+        String debugString() {
             return addTypeString(target, this);
         }
         private Object invoke_V(Object... av) throws Throwable {
@@ -990,9 +1021,48 @@
     }
 
     static
+    MethodHandle selectAlternative(boolean testResult, MethodHandle target, MethodHandle fallback) {
+        return testResult ? target : fallback;
+    }
+
+    static MethodHandle SELECT_ALTERNATIVE;
+    static MethodHandle selectAlternative() {
+        if (SELECT_ALTERNATIVE != null)  return SELECT_ALTERNATIVE;
+        try {
+            SELECT_ALTERNATIVE
+            = IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "selectAlternative",
+                    MethodType.methodType(MethodHandle.class, boolean.class, MethodHandle.class, MethodHandle.class));
+        } catch (ReflectiveOperationException ex) {
+            throw new RuntimeException(ex);
+        }
+        return SELECT_ALTERNATIVE;
+    }
+
+    static
     MethodHandle makeGuardWithTest(MethodHandle test,
                                    MethodHandle target,
                                    MethodHandle fallback) {
+        // gwt(arg...)
+        // [fold]=> continueAfterTest(z=test(arg...), arg...)
+        // [filter]=> (tf=select(z))(arg...)
+        //    where select(z) = select(z, t, f).bindTo(t, f) => z ? t f
+        // [tailcall]=> tf(arg...)
+        assert(test.type().returnType() == boolean.class);
+        MethodType foldTargetType = target.type().insertParameterTypes(0, boolean.class);
+        if (AdapterMethodHandle.canCollectArguments(foldTargetType, test.type(), 0, true)) {
+            // working backwards, as usual:
+            assert(target.type().equals(fallback.type()));
+            MethodHandle tailcall = MethodHandles.exactInvoker(target.type());
+            MethodHandle select = selectAlternative();
+            select = bindArgument(select, 2, fallback);
+            select = bindArgument(select, 1, target);
+            // select(z: boolean) => (z ? target : fallback)
+            MethodHandle filter = filterArgument(tailcall, 0, select);
+            assert(filter.type().parameterType(0) == boolean.class);
+            MethodHandle fold = foldArguments(filter, filter.type().dropParameterTypes(0, 1), 0, test);
+            return fold;
+        }
+        assert(MethodHandleNatives.workaroundWithoutRicochetFrames());  // this code is deprecated
         return GuardWithTest.make(test, target, fallback);
     }
 
@@ -1012,7 +1082,7 @@
             this.catcher = catcher;
         }
         @Override
-        public String toString() {
+        String debugString() {
             return addTypeString(target, this);
         }
         private Object invoke_V(Object... av) throws Throwable {
@@ -1144,11 +1214,12 @@
         } else {
             MethodType gtype = MethodType.genericMethodType(0, true);
             MethodType gcatchType = gtype.insertParameterTypes(0, Throwable.class);
-            MethodHandle gtarget = spreadArguments(target, gtype, 0);
-            MethodHandle gcatcher = spreadArguments(catcher, gcatchType, 1);
+            MethodHandle gtarget = spreadArgumentsFromPos(target, gtype, 0);
+            catcher = catcher.asType(ctype.changeParameterType(0, Throwable.class));
+            MethodHandle gcatcher = spreadArgumentsFromPos(catcher, gcatchType, 1);
             MethodHandle gguard = new GuardWithCatch(GuardWithCatch.VARARGS_INVOKE, gtarget, exType, gcatcher);
             if (gtarget == null || gcatcher == null || gguard == null)  return null;
-            return collectArguments(gguard, type, 0, null);
+            return collectArguments(gguard, type, 0, ValueConversions.varargsArray(nargs)).asType(type);
         }
     }
 
@@ -1178,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/src/share/classes/java/lang/invoke/MethodHandleStatics.java	Fri May 20 16:04:09 2011 -0700
+++ b/src/share/classes/java/lang/invoke/MethodHandleStatics.java	Tue May 24 14:11:38 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/src/share/classes/java/lang/invoke/MethodHandles.java	Fri May 20 16:04:09 2011 -0700
+++ b/src/share/classes/java/lang/invoke/MethodHandles.java	Tue May 24 14:11:38 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;
@@ -1377,6 +1378,9 @@
      */
     public static
     MethodHandle convertArguments(MethodHandle target, MethodType newType) {
+        if (!target.type().isConvertibleTo(newType)) {
+            throw new WrongMethodTypeException("cannot convert "+target+" to "+newType);
+        }
         return MethodHandleImpl.convertArguments(target, newType, 1);
     }
 
@@ -1567,7 +1571,7 @@
         int numSpread = (outargs - spreadPos);
         MethodHandle res = null;
         if (spreadPos >= 0 && numSpread >= 0) {
-            res = MethodHandleImpl.spreadArguments(target, newType, spreadPos);
+            res = MethodHandleImpl.spreadArgumentsFromPos(target, newType, spreadPos);
         }
         if (res == null) {
             throw newIllegalArgumentException("cannot spread "+newType+" to " +oldType);
@@ -2135,7 +2139,7 @@
             int hpc = hargs.size(), tpc = targs.size();
             if (hpc >= tpc || !targs.subList(0, hpc).equals(hargs))
                 throw misMatchedTypes("target and handler types", ttype, htype);
-            handler = dropArguments(handler, hpc, hargs.subList(hpc, tpc));
+            handler = dropArguments(handler, 1+hpc, targs.subList(hpc, tpc));
             htype = handler.type();
         }
         return MethodHandleImpl.makeGuardWithCatch(target, exType, handler);
@@ -2380,9 +2384,4 @@
         }
         return null;
     }
-
-    /*non-public*/
-    static MethodHandle asVarargsCollector(MethodHandle target, Class<?> arrayType) {
-        return MethodHandleImpl.asVarargsCollector(target, arrayType);
-    }
 }
--- a/src/share/classes/java/lang/invoke/MethodType.java	Fri May 20 16:04:09 2011 -0700
+++ b/src/share/classes/java/lang/invoke/MethodType.java	Tue May 24 14:11:38 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/src/share/classes/java/lang/invoke/MethodTypeForm.java	Fri May 20 16:04:09 2011 -0700
+++ b/src/share/classes/java/lang/invoke/MethodTypeForm.java	Tue May 24 14:11:38 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/src/share/classes/java/lang/invoke/SpreadGeneric.java	Fri May 20 16:04:09 2011 -0700
+++ b/src/share/classes/java/lang/invoke/SpreadGeneric.java	Tue May 24 14:11:38 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/src/share/classes/java/lang/invoke/ToGeneric.java	Fri May 20 16:04:09 2011 -0700
+++ b/src/share/classes/java/lang/invoke/ToGeneric.java	Tue May 24 14:11:38 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/src/share/classes/sun/invoke/util/Wrapper.java	Fri May 20 16:04:09 2011 -0700
+++ b/src/share/classes/sun/invoke/util/Wrapper.java	Tue May 24 14:11:38 2011 -0700
@@ -258,7 +258,7 @@
     }
 
     /** Return the wrapper that wraps values into the given wrapper type.
-     *  If it is {@code Object} or an interface, return {@code OBJECT}.
+     *  If it is {@code Object}, return {@code OBJECT}.
      *  Otherwise, it must be a wrapper type.
      *  The type must not be a primitive type.
      *  @throws IllegalArgumentException for unexpected types
@@ -277,8 +277,6 @@
         if (w != null && w.wrapperType == type) {
             return w;
         }
-        if (type.isInterface())
-            return OBJECT;
         return null;
     }
 
--- a/test/java/lang/invoke/6991596/Test6991596.java	Fri May 20 16:04:09 2011 -0700
+++ b/test/java/lang/invoke/6991596/Test6991596.java	Tue May 24 14:11:38 2011 -0700
@@ -51,10 +51,10 @@
         return MethodHandles.lookup().findStatic(CLASS, NAME, MethodType.methodType(ret, arg));
     }
     static MethodHandle getmh2(MethodHandle mh1, Class ret, Class arg) {
-        return MethodHandles.convertArguments(mh1, MethodType.methodType(ret, arg));
+        return MethodHandles.explicitCastArguments(mh1, MethodType.methodType(ret, arg));
     }
     static MethodHandle getmh3(MethodHandle mh1, Class ret, Class arg) {
-        return MethodHandles.convertArguments(mh1, MethodType.methodType(ret, arg));
+        return MethodHandles.explicitCastArguments(mh1, MethodType.methodType(ret, arg));
     }
 
     // test adapter_opt_i2i
--- a/test/java/lang/invoke/InvokeGenericTest.java	Fri May 20 16:04:09 2011 -0700
+++ b/test/java/lang/invoke/InvokeGenericTest.java	Tue May 24 14:11:38 2011 -0700
@@ -53,9 +53,9 @@
         if (vstr != null)  verbosity = Integer.parseInt(vstr);
     }
 
-    public static void main(String... av) throws Throwable {
-        new InvokeGenericTest().testFirst();
-    }
+//    public static void main(String... av) throws Throwable {
+//        new InvokeGenericTest().testFirst();
+//    }
 
     @Test
     public void testFirst() throws Throwable {
@@ -470,8 +470,6 @@
         return allMethodTypes(argc, argc, types);
     }
 
-    interface RandomInterface { }
-
     MethodHandle toString_MH;
 
     @Test
@@ -480,33 +478,62 @@
         toString_MH = LOOKUP.
             findVirtual(Object.class, "toString", MethodType.methodType(String.class));
         Object[] args = { "one", "two" };
-        for (MethodType type : allMethodTypes(2, Object.class, String.class, RandomInterface.class)) {
+        for (MethodType type : allMethodTypes(2, Object.class, String.class, CharSequence.class)) {
             testReferenceConversions(type, args);
         }
     }
     public void testReferenceConversions(MethodType type, Object... args) throws Throwable {
         countTest();
-        if (verbosity > 3)  System.out.println("target type: "+type);
+        int nargs = args.length;
+        List<Object> argList = Arrays.asList(args);
+        String expectString = argList.toString();
+        if (verbosity > 3)  System.out.println("target type: "+type+expectString);
         MethodHandle mh = callable(type.parameterList());
-        MethodHandle tsdrop = MethodHandles.dropArguments(toString_MH, 1, type.parameterList());
-        mh = MethodHandles.foldArguments(tsdrop, mh);
+        mh = MethodHandles.filterReturnValue(mh, toString_MH);
         mh = mh.asType(type);
-        Object res = mh.invoke((String)args[0], (Object)args[1]);
+        Object res = null;
+        if (nargs == 2) {
+            res = mh.invoke((Object)args[0], (Object)args[1]);
+            assertEquals(expectString, res);
+            res = mh.invoke((String)args[0], (Object)args[1]);
+            assertEquals(expectString, res);
+            res = mh.invoke((Object)args[0], (String)args[1]);
+            assertEquals(expectString, res);
+            res = mh.invoke((String)args[0], (String)args[1]);
+            assertEquals(expectString, res);
+            res = mh.invoke((String)args[0], (CharSequence)args[1]);
+            assertEquals(expectString, res);
+            res = mh.invoke((CharSequence)args[0], (Object)args[1]);
+            assertEquals(expectString, res);
+            res = (String) mh.invoke((Object)args[0], (Object)args[1]);
+            assertEquals(expectString, res);
+            res = (String) mh.invoke((String)args[0], (Object)args[1]);
+            assertEquals(expectString, res);
+            res = (CharSequence) mh.invoke((String)args[0], (Object)args[1]);
+            assertEquals(expectString, res);
+        } else {
+            assert(false);  // write this code
+        }
         //System.out.println(res);
-        assertEquals(Arrays.asList(args).toString(), res);
     }
 
 
-    @Test @Ignore("known failure pending 6939861")
+    @Test
     public void testBoxConversions() throws Throwable {
         startTest("testBoxConversions");
         countTest();
         Object[] args = { 1, 2 };
         MethodHandle mh = callable(Object.class, int.class);
-        Object res; List resl;
+        Object res; List resl; int resi;
         res = resl = (List) mh.invoke((int)args[0], (Object)args[1]);
         //System.out.println(res);
         assertEquals(Arrays.asList(args), res);
+        mh = MethodHandles.identity(int.class);
+        mh = MethodHandles.dropArguments(mh, 1, int.class);
+        res = resi = (int) mh.invoke((Object) args[0], (Object) args[1]);
+        assertEquals(args[0], res);
+        res = resi = (int) mh.invoke((int) args[0], (Object) args[1]);
+        assertEquals(args[0], res);
     }
 
 }
--- a/test/java/lang/invoke/MethodHandlesTest.java	Fri May 20 16:04:09 2011 -0700
+++ b/test/java/lang/invoke/MethodHandlesTest.java	Tue May 24 14:11:38 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);
     }