jdk/src/share/classes/java/lang/invoke/MethodHandles.java
changeset 20851 9f284cf7836b
parent 20841 2b188911d712
parent 19804 83170920c07b
child 20853 505b28fe2b98
equal deleted inserted replaced
20850:05fc1bd20e10 20851:9f284cf7836b
    24  */
    24  */
    25 
    25 
    26 package java.lang.invoke;
    26 package java.lang.invoke;
    27 
    27 
    28 import java.lang.reflect.*;
    28 import java.lang.reflect.*;
    29 import java.security.AccessController;
       
    30 import java.security.PrivilegedAction;
       
    31 import java.util.List;
    29 import java.util.List;
    32 import java.util.ArrayList;
    30 import java.util.ArrayList;
    33 import java.util.Arrays;
    31 import java.util.Arrays;
    34 
    32 
    35 import sun.invoke.util.ValueConversions;
    33 import sun.invoke.util.ValueConversions;
    52  * <li>Other factory methods to create method handles that emulate other common JVM operations or control flow patterns.
    50  * <li>Other factory methods to create method handles that emulate other common JVM operations or control flow patterns.
    53  * <li>Wrapper methods which can convert between method handles and interface types.
    51  * <li>Wrapper methods which can convert between method handles and interface types.
    54  * </ul>
    52  * </ul>
    55  * <p>
    53  * <p>
    56  * @author John Rose, JSR 292 EG
    54  * @author John Rose, JSR 292 EG
       
    55  * @since 1.7
    57  */
    56  */
    58 public class MethodHandles {
    57 public class MethodHandles {
    59 
    58 
    60     private MethodHandles() { }  // do not instantiate
    59     private MethodHandles() { }  // do not instantiate
    61 
    60 
    93      * @return a lookup object which is trusted minimally
    92      * @return a lookup object which is trusted minimally
    94      */
    93      */
    95     public static Lookup publicLookup() {
    94     public static Lookup publicLookup() {
    96         return Lookup.PUBLIC_LOOKUP;
    95         return Lookup.PUBLIC_LOOKUP;
    97     }
    96     }
       
    97 
       
    98     /**
       
    99      * Performs an unchecked "crack" of a direct method handle.
       
   100      * The result is as if the user had obtained a lookup object capable enough
       
   101      * to crack the target method handle, called
       
   102      * {@link java.lang.invoke.MethodHandles.Lookup#revealDirect Lookup.revealDirect}
       
   103      * on the target to obtain its symbolic reference, and then called
       
   104      * {@link java.lang.invoke.MethodHandleInfo#reflectAs MethodHandleInfo.reflectAs}
       
   105      * to resolve the symbolic reference to a member.
       
   106      * <p>
       
   107      * If there is a security manager, its {@code checkPermission} method
       
   108      * is called with a {@code ReflectPermission("suppressAccessChecks")} permission.
       
   109      * @param <T> the desired type of the result, either {@link Member} or a subtype
       
   110      * @param target a direct method handle to crack into symbolic reference components
       
   111      * @param expected a class object representing the desired result type {@code T}
       
   112      * @return a reference to the method, constructor, or field object
       
   113      * @exception SecurityException if the caller is not privileged to call {@code setAccessible}
       
   114      * @exception NullPointerException if either argument is {@code null}
       
   115      * @exception IllegalArgumentException if the target is not a direct method handle
       
   116      * @exception ClassCastException if the member is not of the expected type
       
   117      * @since 1.8
       
   118      */
       
   119     public static <T extends Member> T
       
   120     reflectAs(Class<T> expected, MethodHandle target) {
       
   121         SecurityManager smgr = System.getSecurityManager();
       
   122         if (smgr != null)  smgr.checkPermission(ACCESS_PERMISSION);
       
   123         Lookup lookup = Lookup.IMPL_LOOKUP;  // use maximally privileged lookup
       
   124         return lookup.revealDirect(target).reflectAs(expected, lookup);
       
   125     }
       
   126     // Copied from AccessibleObject, as used by Method.setAccessible, etc.:
       
   127     static final private java.security.Permission ACCESS_PERMISSION =
       
   128         new ReflectPermission("suppressAccessChecks");
    98 
   129 
    99     /**
   130     /**
   100      * A <em>lookup object</em> is a factory for creating method handles,
   131      * A <em>lookup object</em> is a factory for creating method handles,
   101      * when the creation requires access checking.
   132      * when the creation requires access checking.
   102      * Method handles do not perform
   133      * Method handles do not perform
   654             // these names require special lookups because of the implicit MethodType argument
   685             // these names require special lookups because of the implicit MethodType argument
   655             if ("invoke".equals(name))
   686             if ("invoke".equals(name))
   656                 return invoker(type);
   687                 return invoker(type);
   657             if ("invokeExact".equals(name))
   688             if ("invokeExact".equals(name))
   658                 return exactInvoker(type);
   689                 return exactInvoker(type);
       
   690             assert(!MemberName.isMethodHandleInvokeName(name));
   659             return null;
   691             return null;
   660         }
   692         }
   661 
   693 
   662         /**
   694         /**
   663          * Produces a method handle which creates an object and initializes it, using
   695          * Produces a method handle which creates an object and initializes it, using
   899          *                                or if the method's variable arity modifier bit
   931          *                                or if the method's variable arity modifier bit
   900          *                                is set and {@code asVarargsCollector} fails
   932          *                                is set and {@code asVarargsCollector} fails
   901          * @throws NullPointerException if the argument is null
   933          * @throws NullPointerException if the argument is null
   902          */
   934          */
   903         public MethodHandle unreflect(Method m) throws IllegalAccessException {
   935         public MethodHandle unreflect(Method m) throws IllegalAccessException {
       
   936             if (m.getDeclaringClass() == MethodHandle.class) {
       
   937                 MethodHandle mh = unreflectForMH(m);
       
   938                 if (mh != null)  return mh;
       
   939             }
   904             MemberName method = new MemberName(m);
   940             MemberName method = new MemberName(m);
   905             byte refKind = method.getReferenceKind();
   941             byte refKind = method.getReferenceKind();
   906             if (refKind == REF_invokeSpecial)
   942             if (refKind == REF_invokeSpecial)
   907                 refKind = REF_invokeVirtual;
   943                 refKind = REF_invokeVirtual;
   908             assert(method.isMethod());
   944             assert(method.isMethod());
   909             Lookup lookup = m.isAccessible() ? IMPL_LOOKUP : this;
   945             Lookup lookup = m.isAccessible() ? IMPL_LOOKUP : this;
   910             return lookup.getDirectMethod(refKind, method.getDeclaringClass(), method, findBoundCallerClass(method));
   946             return lookup.getDirectMethod(refKind, method.getDeclaringClass(), method, findBoundCallerClass(method));
       
   947         }
       
   948         private MethodHandle unreflectForMH(Method m) {
       
   949             // these names require special lookups because they throw UnsupportedOperationException
       
   950             if (MemberName.isMethodHandleInvokeName(m.getName()))
       
   951                 return MethodHandleImpl.fakeMethodHandleInvoke(new MemberName(m));
       
   952             return null;
   911         }
   953         }
   912 
   954 
   913         /**
   955         /**
   914          * Produces a method handle for a reflected method.
   956          * Produces a method handle for a reflected method.
   915          * It will bypass checks for overriding methods on the receiver,
   957          * It will bypass checks for overriding methods on the receiver,
  1009          * @throws IllegalAccessException if access checking fails
  1051          * @throws IllegalAccessException if access checking fails
  1010          * @throws NullPointerException if the argument is null
  1052          * @throws NullPointerException if the argument is null
  1011          */
  1053          */
  1012         public MethodHandle unreflectSetter(Field f) throws IllegalAccessException {
  1054         public MethodHandle unreflectSetter(Field f) throws IllegalAccessException {
  1013             return unreflectField(f, true);
  1055             return unreflectField(f, true);
       
  1056         }
       
  1057 
       
  1058         /**
       
  1059          * Cracks a direct method handle created by this lookup object or a similar one.
       
  1060          * Security and access checks are performed to ensure that this lookup object
       
  1061          * is capable of reproducing the target method handle.
       
  1062          * This means that the cracking may fail if target is a direct method handle
       
  1063          * but was created by an unrelated lookup object.
       
  1064          * @param target a direct method handle to crack into symbolic reference components
       
  1065          * @return a symbolic reference which can be used to reconstruct this method handle from this lookup object
       
  1066          * @exception SecurityException if a security manager is present and it
       
  1067          *                              <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
       
  1068          * @throws IllegalArgumentException if the target is not a direct method handle or if access checking fails
       
  1069          * @exception NullPointerException if the target is {@code null}
       
  1070          * @since 1.8
       
  1071          */
       
  1072         public MethodHandleInfo revealDirect(MethodHandle target) {
       
  1073             MemberName member = target.internalMemberName();
       
  1074             if (member == null || (!member.isResolved() && !member.isMethodHandleInvoke()))
       
  1075                 throw newIllegalArgumentException("not a direct method handle");
       
  1076             Class<?> defc = member.getDeclaringClass();
       
  1077             byte refKind = member.getReferenceKind();
       
  1078             assert(MethodHandleNatives.refKindIsValid(refKind));
       
  1079             if (refKind == REF_invokeSpecial && !target.isInvokeSpecial())
       
  1080                 // Devirtualized method invocation is usually formally virtual.
       
  1081                 // To avoid creating extra MemberName objects for this common case,
       
  1082                 // we encode this extra degree of freedom using MH.isInvokeSpecial.
       
  1083                 refKind = REF_invokeVirtual;
       
  1084             if (refKind == REF_invokeVirtual && defc.isInterface())
       
  1085                 // Symbolic reference is through interface but resolves to Object method (toString, etc.)
       
  1086                 refKind = REF_invokeInterface;
       
  1087             // Check SM permissions and member access before cracking.
       
  1088             try {
       
  1089                 checkSecurityManager(defc, member);
       
  1090                 checkAccess(refKind, defc, member);
       
  1091             } catch (IllegalAccessException ex) {
       
  1092                 throw new IllegalArgumentException(ex);
       
  1093             }
       
  1094             // Produce the handle to the results.
       
  1095             return new InfoFromMemberName(this, member, refKind);
  1014         }
  1096         }
  1015 
  1097 
  1016         /// Helper methods, all package-private.
  1098         /// Helper methods, all package-private.
  1017 
  1099 
  1018         MemberName resolveOrFail(byte refKind, Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
  1100         MemberName resolveOrFail(byte refKind, Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
  1208             return getDirectMethodCommon(refKind, refc, method, false, callerClass);
  1290             return getDirectMethodCommon(refKind, refc, method, false, callerClass);
  1209         }
  1291         }
  1210         private MethodHandle getDirectMethodCommon(byte refKind, Class<?> refc, MemberName method,
  1292         private MethodHandle getDirectMethodCommon(byte refKind, Class<?> refc, MemberName method,
  1211                                                    boolean doRestrict, Class<?> callerClass) throws IllegalAccessException {
  1293                                                    boolean doRestrict, Class<?> callerClass) throws IllegalAccessException {
  1212             checkMethod(refKind, refc, method);
  1294             checkMethod(refKind, refc, method);
  1213             if (method.isMethodHandleInvoke())
  1295             assert(!method.isMethodHandleInvoke());
  1214                 return fakeMethodHandleInvoke(method);
       
  1215 
  1296 
  1216             Class<?> refcAsSuper;
  1297             Class<?> refcAsSuper;
  1217             if (refKind == REF_invokeSpecial &&
  1298             if (refKind == REF_invokeSpecial &&
  1218                 refc != lookupClass() &&
  1299                 refc != lookupClass() &&
       
  1300                 !refc.isInterface() &&
  1219                 refc != (refcAsSuper = lookupClass().getSuperclass()) &&
  1301                 refc != (refcAsSuper = lookupClass().getSuperclass()) &&
  1220                 refc.isAssignableFrom(lookupClass())) {
  1302                 refc.isAssignableFrom(lookupClass())) {
  1221                 assert(!method.getName().equals("<init>"));  // not this code path
  1303                 assert(!method.getName().equals("<init>"));  // not this code path
  1222                 // Per JVMS 6.5, desc. of invokespecial instruction:
  1304                 // Per JVMS 6.5, desc. of invokespecial instruction:
  1223                 // If the method is in a superclass of the LC,
  1305                 // If the method is in a superclass of the LC,
  1240             mh = maybeBindCaller(method, mh, callerClass);
  1322             mh = maybeBindCaller(method, mh, callerClass);
  1241             mh = mh.setVarargs(method);
  1323             mh = mh.setVarargs(method);
  1242             if (doRestrict)
  1324             if (doRestrict)
  1243                 mh = restrictReceiver(method, mh, lookupClass());
  1325                 mh = restrictReceiver(method, mh, lookupClass());
  1244             return mh;
  1326             return mh;
  1245         }
       
  1246         private MethodHandle fakeMethodHandleInvoke(MemberName method) {
       
  1247             return throwException(method.getReturnType(), UnsupportedOperationException.class);
       
  1248         }
  1327         }
  1249         private MethodHandle maybeBindCaller(MemberName method, MethodHandle mh,
  1328         private MethodHandle maybeBindCaller(MemberName method, MethodHandle mh,
  1250                                              Class<?> callerClass)
  1329                                              Class<?> callerClass)
  1251                                              throws IllegalAccessException {
  1330                                              throws IllegalAccessException {
  1252             if (allowedModes == TRUSTED || !MethodHandleNatives.isCallerSensitive(method))
  1331             if (allowedModes == TRUSTED || !MethodHandleNatives.isCallerSensitive(method))