jdk/src/share/classes/java/lang/invoke/MethodHandles.java
changeset 13423 17843fff200d
parent 13044 8411854afc2b
child 13610 28122b96858e
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandles.java	Thu Jul 12 00:12:52 2012 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandles.java	Tue Jul 24 10:47:44 2012 -0700
@@ -26,7 +26,6 @@
 package java.lang.invoke;
 
 import java.lang.reflect.*;
-import sun.invoke.WrapperInstance;
 import sun.invoke.util.ValueConversions;
 import sun.invoke.util.VerifyAccess;
 import sun.invoke.util.Wrapper;
@@ -174,6 +173,8 @@
      * Both {@code MT} and the field type {@code FT} are documented as a parameter named {@code type}.
      * The formal parameter {@code this} stands for the self-reference of type {@code C};
      * if it is present, it is always the leading argument to the method handle invocation.
+     * (In the case of some {@code protected} members, {@code this} may be
+     * restricted in type to the lookup class; see below.)
      * The name {@code arg} stands for all the other method handle arguments.
      * In the code examples for the Core Reflection API, the name {@code thisOrNull}
      * stands for a null reference if the accessed method or field is static,
@@ -244,6 +245,18 @@
      * is exactly equivalent to executing the compiled and resolved call to {@code M}.
      * The same point is true of fields and constructors.
      * <p>
+     * If the desired member is {@code protected}, the usual JVM rules apply,
+     * including the requirement that the lookup class must be either be in the
+     * same package as the desired member, or must inherit that member.
+     * (See the Java Virtual Machine Specification, sections 4.9.2, 5.4.3.5, and 6.4.)
+     * In addition, if the desired member is a non-static field or method
+     * in a different package, the resulting method handle may only be applied
+     * to objects of the lookup class or one of its subclasses.
+     * This requirement is enforced by narrowing the type of the leading
+     * {@code this} parameter from {@code C}
+     * (which will necessarily be a superclass of the lookup class)
+     * to the lookup class itself.
+     * <p>
      * In some cases, access between nested classes is obtained by the Java compiler by creating
      * an wrapper method to access a private method of another class
      * in the same top-level declaration.
@@ -582,19 +595,9 @@
          */
         public
         MethodHandle findStatic(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
-            MemberName method = resolveOrFail(refc, name, type, true);
+            MemberName method = resolveOrFail(REF_invokeStatic, refc, name, type);
             checkSecurityManager(refc, method);  // stack walk magic: do not refactor
-            return accessStatic(refc, method);
-        }
-        private
-        MethodHandle accessStatic(Class<?> refc, MemberName method) throws IllegalAccessException {
-            checkMethod(refc, method, true);
-            return MethodHandleImpl.findMethod(method, false, lookupClassOrNull());
-        }
-        private
-        MethodHandle resolveStatic(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
-            MemberName method = resolveOrFail(refc, name, type, true);
-            return accessStatic(refc, method);
+            return getDirectMethod(REF_invokeStatic, refc, method);
         }
 
         /**
@@ -609,6 +612,11 @@
          * (The dispatching action is identical with that performed by an
          * {@code invokevirtual} or {@code invokeinterface} instruction.)
          * <p>
+         * The first argument will be of type {@code refc} if the lookup
+         * class has full privileges to access the member.  Otherwise
+         * the member must be {@code protected} and the first argument
+         * will be restricted in type to the lookup class.
+         * <p>
          * The returned method handle will have
          * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
          * the method's variable arity modifier bit ({@code 0x0080}) is set.
@@ -636,18 +644,22 @@
          * @throws NullPointerException if any argument is null
          */
         public MethodHandle findVirtual(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
-            MemberName method = resolveOrFail(refc, name, type, false);
+            if (refc == MethodHandle.class) {
+                MethodHandle mh = findVirtualForMH(name, type);
+                if (mh != null)  return mh;
+            }
+            byte refKind = (refc.isInterface() ? REF_invokeInterface : REF_invokeVirtual);
+            MemberName method = resolveOrFail(refKind, refc, name, type);
             checkSecurityManager(refc, method);  // stack walk magic: do not refactor
-            return accessVirtual(refc, method);
+            return getDirectMethod(refKind, refc, method);
         }
-        private MethodHandle resolveVirtual(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
-            MemberName method = resolveOrFail(refc, name, type, false);
-            return accessVirtual(refc, method);
-        }
-        private MethodHandle accessVirtual(Class<?> refc, MemberName method) throws IllegalAccessException {
-            checkMethod(refc, method, false);
-            MethodHandle mh = MethodHandleImpl.findMethod(method, true, lookupClassOrNull());
-            return restrictProtectedReceiver(method, mh);
+        private MethodHandle findVirtualForMH(String name, MethodType type) {
+            // these names require special lookups because of the implicit MethodType argument
+            if ("invoke".equals(name))
+                return invoker(type);
+            if ("invokeExact".equals(name))
+                return exactInvoker(type);
+            return null;
         }
 
         /**
@@ -678,36 +690,9 @@
          */
         public MethodHandle findConstructor(Class<?> refc, MethodType type) throws NoSuchMethodException, IllegalAccessException {
             String name = "<init>";
-            MemberName ctor = resolveOrFail(refc, name, type, false, false, lookupClassOrNull());
+            MemberName ctor = resolveOrFail(REF_newInvokeSpecial, refc, name, type);
             checkSecurityManager(refc, ctor);  // stack walk magic: do not refactor
-            return accessConstructor(refc, ctor);
-        }
-        private MethodHandle accessConstructor(Class<?> refc, MemberName ctor) throws IllegalAccessException {
-            assert(ctor.isConstructor());
-            checkAccess(refc, ctor);
-            MethodHandle rawMH = MethodHandleImpl.findMethod(ctor, false, lookupClassOrNull());
-            MethodHandle allocMH = MethodHandleImpl.makeAllocator(rawMH);
-            return fixVarargs(allocMH, rawMH);
-        }
-        private MethodHandle resolveConstructor(Class<?> refc, MethodType type) throws NoSuchMethodException, IllegalAccessException {
-            String name = "<init>";
-            MemberName ctor = resolveOrFail(refc, name, type, false, false, lookupClassOrNull());
-            return accessConstructor(refc, ctor);
-        }
-
-        /** Return a version of MH which matches matchMH w.r.t. isVarargsCollector. */
-        private static MethodHandle fixVarargs(MethodHandle mh, MethodHandle matchMH) {
-            boolean va1 = mh.isVarargsCollector();
-            boolean va2 = matchMH.isVarargsCollector();
-            if (va1 == va2) {
-                return mh;
-            } else if (va2) {
-                MethodType type = mh.type();
-                int arity = type.parameterCount();
-                return mh.asVarargsCollector(type.parameterType(arity-1));
-            } else {
-                return mh.asFixedArity();
-            }
+            return getDirectConstructor(refc, ctor);
         }
 
         /**
@@ -747,21 +732,10 @@
         public MethodHandle findSpecial(Class<?> refc, String name, MethodType type,
                                         Class<?> specialCaller) throws NoSuchMethodException, IllegalAccessException {
             checkSpecialCaller(specialCaller);
-            MemberName method = resolveOrFail(refc, name, type, false, false, specialCaller);
+            Lookup specialLookup = this.in(specialCaller);
+            MemberName method = specialLookup.resolveOrFail(REF_invokeSpecial, refc, name, type);
             checkSecurityManager(refc, method);  // stack walk magic: do not refactor
-            return accessSpecial(refc, method, specialCaller);
-        }
-        private MethodHandle accessSpecial(Class<?> refc, MemberName method,
-                                           Class<?> specialCaller) throws NoSuchMethodException, IllegalAccessException {
-            checkMethod(refc, method, false);
-            MethodHandle mh = MethodHandleImpl.findMethod(method, false, specialCaller);
-            return restrictReceiver(method, mh, specialCaller);
-        }
-        private MethodHandle resolveSpecial(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
-            Class<?> specialCaller = lookupClass();
-            checkSpecialCaller(specialCaller);
-            MemberName method = resolveOrFail(refc, name, type, false, false, specialCaller);
-            return accessSpecial(refc, method, specialCaller);
+            return specialLookup.getDirectMethod(REF_invokeSpecial, refc, method);
         }
 
         /**
@@ -782,13 +756,9 @@
          * @throws NullPointerException if any argument is null
          */
         public MethodHandle findGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
-            MemberName field = resolveOrFail(refc, name, type, false);
+            MemberName field = resolveOrFail(REF_getField, refc, name, type);
             checkSecurityManager(refc, field);  // stack walk magic: do not refactor
-            return makeAccessor(refc, field, false, false, 0);
-        }
-        private MethodHandle resolveGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
-            MemberName field = resolveOrFail(refc, name, type, false);
-            return makeAccessor(refc, field, false, false, 0);
+            return getDirectField(REF_getField, refc, field);
         }
 
         /**
@@ -809,13 +779,9 @@
          * @throws NullPointerException if any argument is null
          */
         public MethodHandle findSetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
-            MemberName field = resolveOrFail(refc, name, type, false);
+            MemberName field = resolveOrFail(REF_putField, refc, name, type);
             checkSecurityManager(refc, field);  // stack walk magic: do not refactor
-            return makeAccessor(refc, field, false, true, 0);
-        }
-        private MethodHandle resolveSetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
-            MemberName field = resolveOrFail(refc, name, type, false);
-            return makeAccessor(refc, field, false, true, 0);
+            return getDirectField(REF_putField, refc, field);
         }
 
         /**
@@ -835,13 +801,9 @@
          * @throws NullPointerException if any argument is null
          */
         public MethodHandle findStaticGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
-            MemberName field = resolveOrFail(refc, name, type, true);
+            MemberName field = resolveOrFail(REF_getStatic, refc, name, type);
             checkSecurityManager(refc, field);  // stack walk magic: do not refactor
-            return makeAccessor(refc, field, false, false, 1);
-        }
-        private MethodHandle resolveStaticGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
-            MemberName field = resolveOrFail(refc, name, type, true);
-            return makeAccessor(refc, field, false, false, 1);
+            return getDirectField(REF_getStatic, refc, field);
         }
 
         /**
@@ -861,13 +823,9 @@
          * @throws NullPointerException if any argument is null
          */
         public MethodHandle findStaticSetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
-            MemberName field = resolveOrFail(refc, name, type, true);
+            MemberName field = resolveOrFail(REF_putStatic, refc, name, type);
             checkSecurityManager(refc, field);  // stack walk magic: do not refactor
-            return makeAccessor(refc, field, false, true, 1);
-        }
-        private MethodHandle resolveStaticSetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
-            MemberName field = resolveOrFail(refc, name, type, true);
-            return makeAccessor(refc, field, false, true, 1);
+            return getDirectField(REF_putStatic, refc, field);
         }
 
         /**
@@ -918,14 +876,10 @@
          */
         public MethodHandle bind(Object receiver, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
             Class<? extends Object> refc = receiver.getClass(); // may get NPE
-            MemberName method = resolveOrFail(refc, name, type, false);
+            MemberName method = resolveOrFail(REF_invokeSpecial, refc, name, type);
             checkSecurityManager(refc, method);  // stack walk magic: do not refactor
-            checkMethod(refc, method, false);
-            MethodHandle dmh = MethodHandleImpl.findMethod(method, true, lookupClassOrNull());
-            MethodHandle bmh = MethodHandleImpl.bindReceiver(dmh, receiver);
-            if (bmh == null)
-                throw method.makeAccessException("no access", this);
-            return fixVarargs(bmh, dmh);
+            MethodHandle mh = getDirectMethodNoRestrict(REF_invokeSpecial, refc, method);
+            return mh.bindReceiver(receiver).setVarargs(method);
         }
 
         /**
@@ -951,12 +905,12 @@
          */
         public MethodHandle unreflect(Method m) throws IllegalAccessException {
             MemberName method = new MemberName(m);
+            byte refKind = method.getReferenceKind();
+            if (refKind == REF_invokeSpecial)
+                refKind = REF_invokeVirtual;
             assert(method.isMethod());
-            if (m.isAccessible())
-                return MethodHandleImpl.findMethod(method, true, /*no lookupClass*/ null);
-            checkMethod(method.getDeclaringClass(), method, method.isStatic());
-            MethodHandle mh = MethodHandleImpl.findMethod(method, true, lookupClassOrNull());
-            return restrictProtectedReceiver(method, mh);
+            Lookup lookup = m.isAccessible() ? IMPL_LOOKUP : this;
+            return lookup.getDirectMethod(refKind, method.getDeclaringClass(), method);
         }
 
         /**
@@ -982,12 +936,11 @@
          */
         public MethodHandle unreflectSpecial(Method m, Class<?> specialCaller) throws IllegalAccessException {
             checkSpecialCaller(specialCaller);
-            MemberName method = new MemberName(m);
+            Lookup specialLookup = this.in(specialCaller);
+            MemberName method = new MemberName(m, true);
             assert(method.isMethod());
             // ignore m.isAccessible:  this is a new kind of access
-            checkMethod(m.getDeclaringClass(), method, false);
-            MethodHandle mh = MethodHandleImpl.findMethod(method, false, lookupClassOrNull());
-            return restrictReceiver(method, mh, specialCaller);
+            return specialLookup.getDirectMethod(REF_invokeSpecial, method.getDeclaringClass(), method);
         }
 
         /**
@@ -1015,15 +968,8 @@
         public MethodHandle unreflectConstructor(Constructor c) throws IllegalAccessException {
             MemberName ctor = new MemberName(c);
             assert(ctor.isConstructor());
-            MethodHandle rawCtor;
-            if (c.isAccessible()) {
-                rawCtor = MethodHandleImpl.findMethod(ctor, false, /*no lookupClass*/ null);
-            } else {
-                checkAccess(c.getDeclaringClass(), ctor);
-                rawCtor = MethodHandleImpl.findMethod(ctor, false, lookupClassOrNull());
-            }
-            MethodHandle allocator = MethodHandleImpl.makeAllocator(rawCtor);
-            return fixVarargs(allocator, rawCtor);
+            Lookup lookup = c.isAccessible() ? IMPL_LOOKUP : this;
+            return lookup.getDirectConstructor(ctor.getDeclaringClass(), ctor);
         }
 
         /**
@@ -1041,7 +987,15 @@
          * @throws NullPointerException if the argument is null
          */
         public MethodHandle unreflectGetter(Field f) throws IllegalAccessException {
-            return makeAccessor(f.getDeclaringClass(), new MemberName(f), f.isAccessible(), false, -1);
+            return unreflectField(f, false);
+        }
+        private MethodHandle unreflectField(Field f, boolean isSetter) throws IllegalAccessException {
+            MemberName field = new MemberName(f, isSetter);
+            assert(isSetter
+                    ? MethodHandleNatives.refKindIsSetter(field.getReferenceKind())
+                    : MethodHandleNatives.refKindIsGetter(field.getReferenceKind()));
+            Lookup lookup = f.isAccessible() ? IMPL_LOOKUP : this;
+            return lookup.getDirectField(field.getReferenceKind(), f.getDeclaringClass(), field);
         }
 
         /**
@@ -1059,33 +1013,22 @@
          * @throws NullPointerException if the argument is null
          */
         public MethodHandle unreflectSetter(Field f) throws IllegalAccessException {
-            return makeAccessor(f.getDeclaringClass(), new MemberName(f), f.isAccessible(), true, -1);
+            return unreflectField(f, true);
         }
 
         /// Helper methods, all package-private.
 
-        MemberName resolveOrFail(Class<?> refc, String name, Class<?> type, boolean isStatic) throws NoSuchFieldException, IllegalAccessException {
+        MemberName resolveOrFail(byte refKind, Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
             checkSymbolicClass(refc);  // do this before attempting to resolve
             name.getClass(); type.getClass();  // NPE
-            int mods = (isStatic ? Modifier.STATIC : 0);
-            return IMPL_NAMES.resolveOrFail(new MemberName(refc, name, type, mods), true, lookupClassOrNull(),
+            return IMPL_NAMES.resolveOrFail(refKind, new MemberName(refc, name, type, refKind), lookupClassOrNull(),
                                             NoSuchFieldException.class);
         }
 
-        MemberName resolveOrFail(Class<?> refc, String name, MethodType type, boolean isStatic) throws NoSuchMethodException, IllegalAccessException {
+        MemberName resolveOrFail(byte refKind, Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
             checkSymbolicClass(refc);  // do this before attempting to resolve
             name.getClass(); type.getClass();  // NPE
-            int mods = (isStatic ? Modifier.STATIC : 0);
-            return IMPL_NAMES.resolveOrFail(new MemberName(refc, name, type, mods), true, lookupClassOrNull(),
-                                            NoSuchMethodException.class);
-        }
-
-        MemberName resolveOrFail(Class<?> refc, String name, MethodType type, boolean isStatic,
-                                 boolean searchSupers, Class<?> specialCaller) throws NoSuchMethodException, IllegalAccessException {
-            checkSymbolicClass(refc);  // do this before attempting to resolve
-            name.getClass(); type.getClass();  // NPE
-            int mods = (isStatic ? Modifier.STATIC : 0);
-            return IMPL_NAMES.resolveOrFail(new MemberName(refc, name, type, mods), searchSupers, specialCaller,
+            return IMPL_NAMES.resolveOrFail(refKind, new MemberName(refc, name, type, refKind), lookupClassOrNull(),
                                             NoSuchMethodException.class);
         }
 
@@ -1141,7 +1084,8 @@
             // SecurityManager.checkMemberAccess [0]
         }
 
-        void checkMethod(Class<?> refc, MemberName m, boolean wantStatic) throws IllegalAccessException {
+        void checkMethod(byte refKind, Class<?> refc, MemberName m) throws IllegalAccessException {
+            boolean wantStatic = (refKind == REF_invokeStatic);
             String message;
             if (m.isConstructor())
                 message = "expected a method, not a constructor";
@@ -1150,26 +1094,43 @@
             else if (wantStatic != m.isStatic())
                 message = wantStatic ? "expected a static method" : "expected a non-static method";
             else
-                { checkAccess(refc, m); return; }
+                { checkAccess(refKind, refc, m); return; }
             throw m.makeAccessException(message, this);
         }
 
-        void checkAccess(Class<?> refc, MemberName m) throws IllegalAccessException {
+        void checkField(byte refKind, Class<?> refc, MemberName m) throws IllegalAccessException {
+            boolean wantStatic = !MethodHandleNatives.refKindHasReceiver(refKind);
+            String message;
+            if (wantStatic != m.isStatic())
+                message = wantStatic ? "expected a static field" : "expected a non-static field";
+            else
+                { checkAccess(refKind, refc, m); return; }
+            throw m.makeAccessException(message, this);
+        }
+
+        void checkAccess(byte refKind, Class<?> refc, MemberName m) throws IllegalAccessException {
+            assert(m.referenceKindIsConsistentWith(refKind) &&
+                   MethodHandleNatives.refKindIsValid(refKind) &&
+                   (MethodHandleNatives.refKindIsField(refKind) == m.isField()));
             int allowedModes = this.allowedModes;
             if (allowedModes == TRUSTED)  return;
             int mods = m.getModifiers();
+            if (Modifier.isFinal(mods) &&
+                    MethodHandleNatives.refKindIsSetter(refKind))
+                throw m.makeAccessException("unexpected set of a final field", this);
             if (Modifier.isPublic(mods) && Modifier.isPublic(refc.getModifiers()) && allowedModes != 0)
                 return;  // common case
             int requestedModes = fixmods(mods);  // adjust 0 => PACKAGE
-            if ((requestedModes & allowedModes) != 0
-                && VerifyAccess.isMemberAccessible(refc, m.getDeclaringClass(),
-                                                   mods, lookupClass(), allowedModes))
-                return;
-            if (((requestedModes & ~allowedModes) & PROTECTED) != 0
-                && (allowedModes & PACKAGE) != 0
-                && VerifyAccess.isSamePackage(m.getDeclaringClass(), lookupClass()))
+            if ((requestedModes & allowedModes) != 0) {
+                if (VerifyAccess.isMemberAccessible(refc, m.getDeclaringClass(),
+                                                    mods, lookupClass(), allowedModes))
+                    return;
+            } else {
                 // Protected members can also be checked as if they were package-private.
-                return;
+                if ((requestedModes & PROTECTED) != 0 && (allowedModes & PACKAGE) != 0
+                        && VerifyAccess.isSamePackage(m.getDeclaringClass(), lookupClass()))
+                    return;
+            }
             throw m.makeAccessException(accessFailedMessage(refc, m), this);
         }
 
@@ -1198,7 +1159,8 @@
 
         private static final boolean ALLOW_NESTMATE_ACCESS = false;
 
-        void checkSpecialCaller(Class<?> specialCaller) throws IllegalAccessException {
+        private void checkSpecialCaller(Class<?> specialCaller) throws IllegalAccessException {
+            int allowedModes = this.allowedModes;
             if (allowedModes == TRUSTED)  return;
             if ((allowedModes & PRIVATE) == 0
                 || (specialCaller != lookupClass()
@@ -1208,7 +1170,7 @@
                     makeAccessException("no private access for invokespecial", this);
         }
 
-        MethodHandle restrictProtectedReceiver(MemberName method, MethodHandle mh) throws IllegalAccessException {
+        private boolean restrictProtectedReceiver(MemberName method) {
             // The accessing class only has the right to use a protected member
             // on itself or a subclass.  Enforce that restriction, from JVMS 5.4.4, etc.
             if (!method.isProtected() || method.isStatic()
@@ -1217,52 +1179,82 @@
                 || VerifyAccess.isSamePackage(method.getDeclaringClass(), lookupClass())
                 || (ALLOW_NESTMATE_ACCESS &&
                     VerifyAccess.isSamePackageMember(method.getDeclaringClass(), lookupClass())))
-                return mh;
-            else
-                return restrictReceiver(method, mh, lookupClass());
+                return false;
+            return true;
         }
-        MethodHandle restrictReceiver(MemberName method, MethodHandle mh, Class<?> caller) throws IllegalAccessException {
+        private MethodHandle restrictReceiver(MemberName method, MethodHandle mh, Class<?> caller) throws IllegalAccessException {
             assert(!method.isStatic());
-            Class<?> defc = method.getDeclaringClass();  // receiver type of mh is too wide
-            if (defc.isInterface() || !defc.isAssignableFrom(caller)) {
+            // receiver type of mh is too wide; narrow to caller
+            if (!method.getDeclaringClass().isAssignableFrom(caller)) {
                 throw method.makeAccessException("caller class must be a subclass below the method", caller);
             }
             MethodType rawType = mh.type();
             if (rawType.parameterType(0) == caller)  return mh;
             MethodType narrowType = rawType.changeParameterType(0, caller);
-            MethodHandle narrowMH = MethodHandleImpl.convertArguments(mh, narrowType, rawType, 0);
-            return fixVarargs(narrowMH, mh);
+            return mh.viewAsType(narrowType);
         }
 
-        MethodHandle makeAccessor(Class<?> refc, MemberName field,
-                                  boolean trusted, boolean isSetter,
-                                  int checkStatic) throws IllegalAccessException {
-            assert(field.isField());
-            if (checkStatic >= 0 && (checkStatic != 0) != field.isStatic())
-                throw field.makeAccessException((checkStatic != 0)
-                                                ? "expected a static field"
-                                                : "expected a non-static field", this);
-            if (trusted)
-                return MethodHandleImpl.accessField(field, isSetter, /*no lookupClass*/ null);
-            checkAccess(refc, field);
-            MethodHandle mh = MethodHandleImpl.accessField(field, isSetter, lookupClassOrNull());
-            return restrictProtectedReceiver(field, mh);
+        private MethodHandle getDirectMethod(byte refKind, Class<?> refc, MemberName method) throws IllegalAccessException {
+            return getDirectMethodCommon(refKind, refc, method,
+                    (refKind == REF_invokeSpecial ||
+                        (MethodHandleNatives.refKindHasReceiver(refKind) &&
+                            restrictProtectedReceiver(method))));
+        }
+        private MethodHandle getDirectMethodNoRestrict(byte refKind, Class<?> refc, MemberName method) throws IllegalAccessException {
+            return getDirectMethodCommon(refKind, refc, method, false);
+        }
+        private MethodHandle getDirectMethodCommon(byte refKind, Class<?> refc, MemberName method,
+                                                   boolean doRestrict) throws IllegalAccessException {
+            checkMethod(refKind, refc, method);
+            if (method.isMethodHandleInvoke())
+                return fakeMethodHandleInvoke(method);
+            MethodHandle mh = DirectMethodHandle.make(refc, method);
+            mh = mh.setVarargs(method);
+            if (doRestrict)
+                mh = restrictReceiver(method, mh, lookupClass());
+            return mh;
+        }
+        private MethodHandle fakeMethodHandleInvoke(MemberName method) {
+            return throwException(method.getReturnType(), UnsupportedOperationException.class);
+        }
+        private MethodHandle getDirectField(byte refKind, Class<?> refc, MemberName field) throws IllegalAccessException {
+            checkField(refKind, refc, field);
+            MethodHandle mh = DirectMethodHandle.make(refc, field);
+            boolean doRestrict = (MethodHandleNatives.refKindHasReceiver(refKind) &&
+                                    restrictProtectedReceiver(field));
+            if (doRestrict)
+                mh = restrictReceiver(field, mh, lookupClass());
+            return mh;
+        }
+        private MethodHandle getDirectConstructor(Class<?> refc, MemberName ctor) throws IllegalAccessException {
+            assert(ctor.isConstructor());
+            checkAccess(REF_newInvokeSpecial, refc, ctor);
+            return DirectMethodHandle.make(ctor).setVarargs(ctor);
         }
 
         /** Hook called from the JVM (via MethodHandleNatives) to link MH constants:
          */
         /*non-public*/
-        MethodHandle linkMethodHandleConstant(int refKind, Class<?> defc, String name, Object type) throws ReflectiveOperationException {
-            switch (refKind) {
-            case REF_getField:          return resolveGetter(       defc, name, (Class<?>)   type );
-            case REF_getStatic:         return resolveStaticGetter( defc, name, (Class<?>)   type );
-            case REF_putField:          return resolveSetter(       defc, name, (Class<?>)   type );
-            case REF_putStatic:         return resolveStaticSetter( defc, name, (Class<?>)   type );
-            case REF_invokeVirtual:     return resolveVirtual(      defc, name, (MethodType) type );
-            case REF_invokeStatic:      return resolveStatic(       defc, name, (MethodType) type );
-            case REF_invokeSpecial:     return resolveSpecial(      defc, name, (MethodType) type );
-            case REF_newInvokeSpecial:  return resolveConstructor(  defc,       (MethodType) type );
-            case REF_invokeInterface:   return resolveVirtual(      defc, name, (MethodType) type );
+        MethodHandle linkMethodHandleConstant(byte refKind, Class<?> defc, String name, Object type) throws ReflectiveOperationException {
+            MemberName resolved = null;
+            if (type instanceof MemberName) {
+                resolved = (MemberName) type;
+                if (!resolved.isResolved())  throw new InternalError("unresolved MemberName");
+                assert(name == null || name.equals(resolved.getName()));
+            }
+            if (MethodHandleNatives.refKindIsField(refKind)) {
+                MemberName field = (resolved != null) ? resolved
+                        : resolveOrFail(refKind, defc, name, (Class<?>) type);
+                return getDirectField(refKind, defc, field);
+            } else if (MethodHandleNatives.refKindIsMethod(refKind)) {
+                MemberName method = (resolved != null) ? resolved
+                        : resolveOrFail(refKind, defc, name, (MethodType) type);
+                return getDirectMethod(refKind, defc, method);
+            } else if (refKind == REF_newInvokeSpecial) {
+                assert(name == null || name.equals("<init>"));
+                MemberName ctor = (resolved != null) ? resolved
+                        : resolveOrFail(REF_newInvokeSpecial, defc, name, (MethodType) type);
+                return getDirectConstructor(defc, ctor);
             }
             // oops
             throw new ReflectiveOperationException("bad MethodHandle constant #"+refKind+" "+name+" : "+type);
@@ -1281,7 +1273,7 @@
      */
     public static
     MethodHandle arrayElementGetter(Class<?> arrayClass) throws IllegalArgumentException {
-        return MethodHandleImpl.accessArrayElement(arrayClass, false);
+        return MethodHandleImpl.makeArrayElementAccessor(arrayClass, false);
     }
 
     /**
@@ -1295,7 +1287,7 @@
      */
     public static
     MethodHandle arrayElementSetter(Class<?> arrayClass) throws IllegalArgumentException {
-        return MethodHandleImpl.accessArrayElement(arrayClass, true);
+        return MethodHandleImpl.makeArrayElementAccessor(arrayClass, true);
     }
 
     /// method handle invocation (reflective style)
@@ -1422,78 +1414,12 @@
         return type.invokers().generalInvoker();
     }
 
-    /**
-     * Perform value checking, exactly as if for an adapted method handle.
-     * It is assumed that the given value is either null, of type T0,
-     * or (if T0 is primitive) of the wrapper class corresponding to T0.
-     * The following checks and conversions are made:
-     * <ul>
-     * <li>If T0 and T1 are references, then a cast to T1 is applied.
-     *     (The types do not need to be related in any particular way.)
-     * <li>If T0 and T1 are primitives, then a widening or narrowing
-     *     conversion is applied, if one exists.
-     * <li>If T0 is a primitive and T1 a reference, and
-     *     T0 has a wrapper class TW, a boxing conversion to TW is applied,
-     *     possibly followed by a reference conversion.
-     *     T1 must be TW or a supertype.
-     * <li>If T0 is a reference and T1 a primitive, and
-     *     T1 has a wrapper class TW, an unboxing conversion is applied,
-     *     possibly preceded by a reference conversion.
-     *     T0 must be TW or a supertype.
-     * <li>If T1 is void, the return value is discarded
-     * <li>If T0 is void and T1 a reference, a null value is introduced.
-     * <li>If T0 is void and T1 a primitive, a zero value is introduced.
-     * </ul>
-     * If the value is discarded, null will be returned.
-     * @param valueType
-     * @param value
-     * @return the value, converted if necessary
-     * @throws java.lang.ClassCastException if a cast fails
-     */
-    // FIXME: This is used in just one place.  Refactor away.
-    static
-    <T0, T1> T1 checkValue(Class<T0> t0, Class<T1> t1, Object value)
-       throws ClassCastException
-    {
-        if (t0 == t1) {
-            // no conversion needed; just reassert the same type
-            if (t0.isPrimitive())
-                return Wrapper.asPrimitiveType(t1).cast(value);
-            else
-                return Wrapper.OBJECT.convert(value, t1);
-        }
-        boolean prim0 = t0.isPrimitive(), prim1 = t1.isPrimitive();
-        if (!prim0) {
-            // check contract with caller
-            Wrapper.OBJECT.convert(value, t0);
-            if (!prim1) {
-                return Wrapper.OBJECT.convert(value, t1);
-            }
-            // convert reference to primitive by unboxing
-            Wrapper w1 = Wrapper.forPrimitiveType(t1);
-            return w1.convert(value, t1);
-        }
-        // check contract with caller:
-        Wrapper.asWrapperType(t0).cast(value);
-        Wrapper w1 = Wrapper.forPrimitiveType(t1);
-        return w1.convert(value, t1);
+    static /*non-public*/
+    MethodHandle basicInvoker(MethodType type) {
+        return type.form().basicInvoker();
     }
 
-    // FIXME: Delete this.  It is used only for insertArguments & bindTo.
-    // Replace by a more standard check.
-    static
-    Object checkValue(Class<?> T1, Object value)
-       throws ClassCastException
-    {
-        Class<?> T0;
-        if (value == null)
-            T0 = Object.class;
-        else
-            T0 = value.getClass();
-        return checkValue(T0, T1, value);
-    }
-
-    /// method handle modification (creation from other method handles)
+     /// method handle modification (creation from other method handles)
 
     /**
      * Produces a method handle which adapts the type of the
@@ -1541,7 +1467,10 @@
      */
     public static
     MethodHandle explicitCastArguments(MethodHandle target, MethodType newType) {
-        return MethodHandleImpl.convertArguments(target, newType, 2);
+        if (!target.type().isCastableTo(newType)) {
+            throw new WrongMethodTypeException("cannot explicitly cast "+target+" to "+newType);
+        }
+        return MethodHandleImpl.makePairwiseConvert(target, newType, 2);
     }
 
     /**
@@ -1605,11 +1534,8 @@
      */
     public static
     MethodHandle permuteArguments(MethodHandle target, MethodType newType, int... reorder) {
-        MethodType oldType = target.type();
-        checkReorder(reorder, newType, oldType);
-        return MethodHandleImpl.permuteArguments(target,
-                                                 newType, oldType,
-                                                 reorder);
+        checkReorder(reorder, newType, target.type());
+        return target.permuteArguments(newType, reorder);
     }
 
     private static void checkReorder(int[] reorder, MethodType newType, MethodType oldType) {
@@ -1678,8 +1604,7 @@
         else if (type.isPrimitive())
             return ValueConversions.identity(Wrapper.forPrimitiveType(type));
         else
-            return AdapterMethodHandle.makeRetypeRaw(
-                    MethodType.methodType(type, type), ValueConversions.identity());
+            return MethodHandleImpl.makeReferenceIdentity(type);
     }
 
     /**
@@ -1725,18 +1650,26 @@
         MethodHandle result = target;
         for (int i = 0; i < insCount; i++) {
             Object value = values[i];
-            Class<?> valueType = oldType.parameterType(pos+i);
-            value = checkValue(valueType, value);
-            if (pos == 0 && !valueType.isPrimitive()) {
-                // At least for now, make bound method handles a special case.
-                MethodHandle bmh = MethodHandleImpl.bindReceiver(result, value);
-                if (bmh != null) {
-                    result = bmh;
-                    continue;
+            Class<?> ptype = oldType.parameterType(pos+i);
+            if (ptype.isPrimitive()) {
+                char btype = 'I';
+                Wrapper w = Wrapper.forPrimitiveType(ptype);
+                switch (w) {
+                case LONG:    btype = 'J'; break;
+                case FLOAT:   btype = 'F'; break;
+                case DOUBLE:  btype = 'D'; break;
                 }
-                // else fall through to general adapter machinery
+                // perform unboxing and/or primitive conversion
+                value = w.convert(value, ptype);
+                result = result.bindArgument(pos, btype, value);
+                continue;
             }
-            result = MethodHandleImpl.bindArgument(result, pos, value);
+            value = ptype.cast(value);  // throw CCE if needed
+            if (pos == 0) {
+                result = result.bindReceiver(value);
+            } else {
+                result = result.bindArgument(pos, 'L', value);
+            }
         }
         return result;
     }
@@ -1786,16 +1719,17 @@
     public static
     MethodHandle dropArguments(MethodHandle target, int pos, List<Class<?>> valueTypes) {
         MethodType oldType = target.type();  // get NPE
-        if (valueTypes.size() == 0)  return target;
+        int dropped = valueTypes.size();
+        MethodType.checkSlotCount(dropped);
+        if (dropped == 0)  return target;
         int outargs = oldType.parameterCount();
-        int inargs  = outargs + valueTypes.size();
+        int inargs  = outargs + dropped;
         if (pos < 0 || pos >= inargs)
             throw newIllegalArgumentException("no argument type to remove");
-        ArrayList<Class<?>> ptypes =
-                new ArrayList<Class<?>>(oldType.parameterList());
+        ArrayList<Class<?>> ptypes = new ArrayList<>(oldType.parameterList());
         ptypes.addAll(pos, valueTypes);
         MethodType newType = MethodType.methodType(oldType.returnType(), ptypes);
-        return MethodHandleImpl.dropArguments(target, newType, pos);
+        return target.dropArguments(newType, pos, dropped);
     }
 
     /**
@@ -1939,7 +1873,7 @@
         if (filterType.parameterCount() != 1
             || filterType.returnType() != targetType.parameterType(pos))
             throw newIllegalArgumentException("target and filter types do not match", targetType, filterType);
-        return MethodHandleImpl.filterArgument(target, pos, filter);
+        return MethodHandleImpl.makeCollectArguments(target, filter, pos, false);
     }
 
     /**
@@ -2011,10 +1945,7 @@
             throw newIllegalArgumentException("target and filter types do not match", target, filter);
         // result = fold( lambda(retval, arg...) { filter(retval) },
         //                lambda(        arg...) { target(arg...) } )
-        MethodType newType = targetType.changeReturnType(filterType.returnType());
-        MethodHandle result = null;
-        assert(AdapterMethodHandle.canCollectArguments(filterType, targetType, 0, false));
-        return AdapterMethodHandle.makeCollectArguments(filter, target, 0, false);
+        return MethodHandleImpl.makeCollectArguments(filter, target, 0, false);
     }
 
     /**
@@ -2112,9 +2043,7 @@
         if (!ok)
             throw misMatchedTypes("target and combiner types", targetType, combinerType);
         MethodType newType = targetType.dropParameterTypes(foldPos, afterInsertPos);
-        MethodHandle res = MethodHandleImpl.foldArguments(target, newType, foldPos, combiner);
-        if (res == null)  throw newIllegalArgumentException("cannot fold from "+newType+" to " +targetType);
-        return res;
+        return MethodHandleImpl.makeCollectArguments(target, combiner, foldPos, true);
     }
 
     /**
@@ -2255,6 +2184,8 @@
      */
     public static
     MethodHandle throwException(Class<?> returnType, Class<? extends Throwable> exType) {
+        if (!Throwable.class.isAssignableFrom(exType))
+            throw new ClassCastException(exType.getName());
         return MethodHandleImpl.throwException(MethodType.methodType(returnType, exType));
     }
 }