jdk/src/share/classes/java/lang/invoke/MethodHandles.java
changeset 19804 83170920c07b
parent 18766 28c62f5e9a47
child 20851 9f284cf7836b
child 20527 d241258cfbcb
equal deleted inserted replaced
19803:db1de252632d 19804:83170920c07b
    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
   645             // these names require special lookups because of the implicit MethodType argument
   676             // these names require special lookups because of the implicit MethodType argument
   646             if ("invoke".equals(name))
   677             if ("invoke".equals(name))
   647                 return invoker(type);
   678                 return invoker(type);
   648             if ("invokeExact".equals(name))
   679             if ("invokeExact".equals(name))
   649                 return exactInvoker(type);
   680                 return exactInvoker(type);
       
   681             assert(!MemberName.isMethodHandleInvokeName(name));
   650             return null;
   682             return null;
   651         }
   683         }
   652 
   684 
   653         /**
   685         /**
   654          * Produces a method handle which creates an object and initializes it, using
   686          * Produces a method handle which creates an object and initializes it, using
   890          *                                or if the method's variable arity modifier bit
   922          *                                or if the method's variable arity modifier bit
   891          *                                is set and {@code asVarargsCollector} fails
   923          *                                is set and {@code asVarargsCollector} fails
   892          * @throws NullPointerException if the argument is null
   924          * @throws NullPointerException if the argument is null
   893          */
   925          */
   894         public MethodHandle unreflect(Method m) throws IllegalAccessException {
   926         public MethodHandle unreflect(Method m) throws IllegalAccessException {
       
   927             if (m.getDeclaringClass() == MethodHandle.class) {
       
   928                 MethodHandle mh = unreflectForMH(m);
       
   929                 if (mh != null)  return mh;
       
   930             }
   895             MemberName method = new MemberName(m);
   931             MemberName method = new MemberName(m);
   896             byte refKind = method.getReferenceKind();
   932             byte refKind = method.getReferenceKind();
   897             if (refKind == REF_invokeSpecial)
   933             if (refKind == REF_invokeSpecial)
   898                 refKind = REF_invokeVirtual;
   934                 refKind = REF_invokeVirtual;
   899             assert(method.isMethod());
   935             assert(method.isMethod());
   900             Lookup lookup = m.isAccessible() ? IMPL_LOOKUP : this;
   936             Lookup lookup = m.isAccessible() ? IMPL_LOOKUP : this;
   901             return lookup.getDirectMethod(refKind, method.getDeclaringClass(), method, findBoundCallerClass(method));
   937             return lookup.getDirectMethod(refKind, method.getDeclaringClass(), method, findBoundCallerClass(method));
       
   938         }
       
   939         private MethodHandle unreflectForMH(Method m) {
       
   940             // these names require special lookups because they throw UnsupportedOperationException
       
   941             if (MemberName.isMethodHandleInvokeName(m.getName()))
       
   942                 return MethodHandleImpl.fakeMethodHandleInvoke(new MemberName(m));
       
   943             return null;
   902         }
   944         }
   903 
   945 
   904         /**
   946         /**
   905          * Produces a method handle for a reflected method.
   947          * Produces a method handle for a reflected method.
   906          * It will bypass checks for overriding methods on the receiver,
   948          * It will bypass checks for overriding methods on the receiver,
  1000          * @throws IllegalAccessException if access checking fails
  1042          * @throws IllegalAccessException if access checking fails
  1001          * @throws NullPointerException if the argument is null
  1043          * @throws NullPointerException if the argument is null
  1002          */
  1044          */
  1003         public MethodHandle unreflectSetter(Field f) throws IllegalAccessException {
  1045         public MethodHandle unreflectSetter(Field f) throws IllegalAccessException {
  1004             return unreflectField(f, true);
  1046             return unreflectField(f, true);
       
  1047         }
       
  1048 
       
  1049         /**
       
  1050          * Cracks a direct method handle created by this lookup object or a similar one.
       
  1051          * Security and access checks are performed to ensure that this lookup object
       
  1052          * is capable of reproducing the target method handle.
       
  1053          * This means that the cracking may fail if target is a direct method handle
       
  1054          * but was created by an unrelated lookup object.
       
  1055          * @param target a direct method handle to crack into symbolic reference components
       
  1056          * @return a symbolic reference which can be used to reconstruct this method handle from this lookup object
       
  1057          * @exception SecurityException if a security manager is present and it
       
  1058          *                              <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
       
  1059          * @throws IllegalArgumentException if the target is not a direct method handle or if access checking fails
       
  1060          * @exception NullPointerException if the target is {@code null}
       
  1061          * @since 1.8
       
  1062          */
       
  1063         public MethodHandleInfo revealDirect(MethodHandle target) {
       
  1064             MemberName member = target.internalMemberName();
       
  1065             if (member == null || (!member.isResolved() && !member.isMethodHandleInvoke()))
       
  1066                 throw newIllegalArgumentException("not a direct method handle");
       
  1067             Class<?> defc = member.getDeclaringClass();
       
  1068             byte refKind = member.getReferenceKind();
       
  1069             assert(MethodHandleNatives.refKindIsValid(refKind));
       
  1070             if (refKind == REF_invokeSpecial && !target.isInvokeSpecial())
       
  1071                 // Devirtualized method invocation is usually formally virtual.
       
  1072                 // To avoid creating extra MemberName objects for this common case,
       
  1073                 // we encode this extra degree of freedom using MH.isInvokeSpecial.
       
  1074                 refKind = REF_invokeVirtual;
       
  1075             if (refKind == REF_invokeVirtual && defc.isInterface())
       
  1076                 // Symbolic reference is through interface but resolves to Object method (toString, etc.)
       
  1077                 refKind = REF_invokeInterface;
       
  1078             // Check SM permissions and member access before cracking.
       
  1079             try {
       
  1080                 checkSecurityManager(defc, member);
       
  1081                 checkAccess(refKind, defc, member);
       
  1082             } catch (IllegalAccessException ex) {
       
  1083                 throw new IllegalArgumentException(ex);
       
  1084             }
       
  1085             // Produce the handle to the results.
       
  1086             return new InfoFromMemberName(this, member, refKind);
  1005         }
  1087         }
  1006 
  1088 
  1007         /// Helper methods, all package-private.
  1089         /// Helper methods, all package-private.
  1008 
  1090 
  1009         MemberName resolveOrFail(byte refKind, Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
  1091         MemberName resolveOrFail(byte refKind, Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
  1199             return getDirectMethodCommon(refKind, refc, method, false, callerClass);
  1281             return getDirectMethodCommon(refKind, refc, method, false, callerClass);
  1200         }
  1282         }
  1201         private MethodHandle getDirectMethodCommon(byte refKind, Class<?> refc, MemberName method,
  1283         private MethodHandle getDirectMethodCommon(byte refKind, Class<?> refc, MemberName method,
  1202                                                    boolean doRestrict, Class<?> callerClass) throws IllegalAccessException {
  1284                                                    boolean doRestrict, Class<?> callerClass) throws IllegalAccessException {
  1203             checkMethod(refKind, refc, method);
  1285             checkMethod(refKind, refc, method);
  1204             if (method.isMethodHandleInvoke())
  1286             assert(!method.isMethodHandleInvoke());
  1205                 return fakeMethodHandleInvoke(method);
       
  1206 
  1287 
  1207             Class<?> refcAsSuper;
  1288             Class<?> refcAsSuper;
  1208             if (refKind == REF_invokeSpecial &&
  1289             if (refKind == REF_invokeSpecial &&
  1209                 refc != lookupClass() &&
  1290                 refc != lookupClass() &&
       
  1291                 !refc.isInterface() &&
  1210                 refc != (refcAsSuper = lookupClass().getSuperclass()) &&
  1292                 refc != (refcAsSuper = lookupClass().getSuperclass()) &&
  1211                 refc.isAssignableFrom(lookupClass())) {
  1293                 refc.isAssignableFrom(lookupClass())) {
  1212                 assert(!method.getName().equals("<init>"));  // not this code path
  1294                 assert(!method.getName().equals("<init>"));  // not this code path
  1213                 // Per JVMS 6.5, desc. of invokespecial instruction:
  1295                 // Per JVMS 6.5, desc. of invokespecial instruction:
  1214                 // If the method is in a superclass of the LC,
  1296                 // If the method is in a superclass of the LC,
  1231             mh = maybeBindCaller(method, mh, callerClass);
  1313             mh = maybeBindCaller(method, mh, callerClass);
  1232             mh = mh.setVarargs(method);
  1314             mh = mh.setVarargs(method);
  1233             if (doRestrict)
  1315             if (doRestrict)
  1234                 mh = restrictReceiver(method, mh, lookupClass());
  1316                 mh = restrictReceiver(method, mh, lookupClass());
  1235             return mh;
  1317             return mh;
  1236         }
       
  1237         private MethodHandle fakeMethodHandleInvoke(MemberName method) {
       
  1238             return throwException(method.getReturnType(), UnsupportedOperationException.class);
       
  1239         }
  1318         }
  1240         private MethodHandle maybeBindCaller(MemberName method, MethodHandle mh,
  1319         private MethodHandle maybeBindCaller(MemberName method, MethodHandle mh,
  1241                                              Class<?> callerClass)
  1320                                              Class<?> callerClass)
  1242                                              throws IllegalAccessException {
  1321                                              throws IllegalAccessException {
  1243             if (allowedModes == TRUSTED || !MethodHandleNatives.isCallerSensitive(method))
  1322             if (allowedModes == TRUSTED || !MethodHandleNatives.isCallerSensitive(method))