jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java
changeset 9752 88ab34b6da6d
parent 9731 d0f7a3e441c4
child 9780 6fc3b49cfee4
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java	Tue May 17 19:48:19 2011 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java	Thu May 26 17:37:36 2011 -0700
@@ -82,12 +82,17 @@
         }
         DirectMethodHandle mh = new DirectMethodHandle(mtype, method, doDispatch, lookupClass);
         if (!mh.isValid())
-            throw method.makeAccessException("no access", lookupClass);
+            throw method.makeAccessException("no direct method handle", lookupClass);
         assert(mh.type() == mtype);
         if (!method.isVarargs())
             return mh;
-        else
-            return mh.asVarargsCollector(mtype.parameterType(mtype.parameterCount()-1));
+        int argc = mtype.parameterCount();
+        if (argc != 0) {
+            Class<?> arrayType = mtype.parameterType(argc-1);
+            if (arrayType.isArray())
+                return AdapterMethodHandle.makeVarargsCollector(mh, arrayType);
+        }
+        throw method.makeAccessException("cannot make variable arity", null);
     }
 
     static
@@ -485,14 +490,14 @@
      */
     static
     MethodHandle bindReceiver(MethodHandle target, Object receiver) {
+        if (receiver == null)  return null;
         if (target instanceof AdapterMethodHandle &&
             ((AdapterMethodHandle)target).conversionOp() == MethodHandleNatives.Constants.OP_RETYPE_ONLY
             ) {
             Object info = MethodHandleNatives.getTargetInfo(target);
             if (info instanceof DirectMethodHandle) {
                 DirectMethodHandle dmh = (DirectMethodHandle) info;
-                if (receiver == null ||
-                    dmh.type().parameterType(0).isAssignableFrom(receiver.getClass())) {
+                if (dmh.type().parameterType(0).isAssignableFrom(receiver.getClass())) {
                     MethodHandle bmh = new BoundMethodHandle(dmh, receiver, 0);
                     MethodType newType = target.type().dropParameterTypes(0, 1);
                     return convertArguments(bmh, newType, bmh.type(), 0);
@@ -698,7 +703,9 @@
             if (target == null)  throw newIllegalArgumentException("cannot drop");
             oldType = target.type();
         }
-        return convertArguments(target, newType, oldType, 0);
+        target = convertArguments(target, newType, oldType, 0);
+        assert(target != null);
+        return target;
     }
 
     /*non-public*/ static
@@ -907,14 +914,16 @@
             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 boolean preferRicochetFrame(MethodType type) {
+            return (type.parameterCount() >= INVOKES.length || type.hasPrimitives());
+        }
         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) {
+                if (preferRicochetFrame(type))
+                    assert(MethodHandleNatives.workaroundWithoutRicochetFrames());  // this code is deprecated
                 MethodHandle invoke = INVOKES[nargs];
                 MethodType gtype = type.generic();
                 assert(invoke.type().dropParameterTypes(0,1) == gtype);
@@ -925,6 +934,7 @@
                 MethodHandle gguard = new GuardWithTest(invoke, gtest, gtarget, gfallback);
                 return convertArguments(gguard, type, gtype, 0);
             } else {
+                assert(MethodHandleNatives.workaroundWithoutRicochetFrames());  // this code is deprecated
                 MethodHandle invoke = VARARGS_INVOKE;
                 MethodType gtype = MethodType.genericMethodType(1);
                 assert(invoke.type().dropParameterTypes(0,1) == gtype);
@@ -1048,8 +1058,10 @@
         //    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)) {
+        MethodType targetType = target.type();
+        MethodType foldTargetType = targetType.insertParameterTypes(0, boolean.class);
+        if (AdapterMethodHandle.canCollectArguments(foldTargetType, test.type(), 0, true)
+            && GuardWithTest.preferRicochetFrame(targetType)) {
             // working backwards, as usual:
             assert(target.type().equals(fallback.type()));
             MethodHandle tailcall = MethodHandles.exactInvoker(target.type());
@@ -1062,7 +1074,6 @@
             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);
     }